From e0ecd680a02ccf9e3ef46c4c82b2336d9509426f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 15:41:16 +0900 Subject: [PATCH 01/16] sw_engine: fix crash at merge shape test increased spare cell memory for rasterizing. Change-Id: I391dfbfae0ef028d213c55fe1ceca023e272e676 --- src/lib/sw_engine/tvgSwRle.cpp | 3 ++- test/testMergeShapes.cpp | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 3991fff..02870c3 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -671,7 +671,8 @@ static bool _genRle(RleWorker& rw) SwRleData* rleRender(const SwShape& sdata, const SwSize& clip) { - constexpr auto RENDER_POOL_SIZE = 16384L; + //Please adjust when you out of cell memory (default: 16384L) + constexpr auto RENDER_POOL_SIZE = 166641L; constexpr auto BAND_SIZE = 40; auto outline = sdata.outline; diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index 549ea9e..b37440b 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -20,10 +20,9 @@ void tvgtest() auto shape1 = tvg::ShapeNode::gen(); shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius shape1->appendRect(100, 100, 300, 300, 100); //x, y, w, h, cornerRadius - shape1->appendCircle(500, 500, 100, 100); //cx, cy, radiusW, radiusH - //FIXME: eeek! crash! - // shape1->appendCircle(400, 600, 170, 100); //cx, cy, radiusW, radiusH - shape1->fill(255, 0, 0, 255); //r, g, b, a + 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, 255); //r, g, b, a /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare -- 2.7.4 From 9b8ab42e545cac7514caa7893312d2beb03f1e02 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 18:31:51 +0900 Subject: [PATCH 02/16] common shape: support path appending it's usage may require a little handy but The path data is very low manipulated, its usage may require a little handy, but appedingPath() is designed for performance. Also added testPath. Change-Id: Ifd929d48506926e3f529198c0b40ee8f922835d4 --- .gitignore | 1 + inc/tizenvg.h | 1 + src/lib/tvgCommon.h | 1 + src/lib/tvgShapeNode.cpp | 24 ++++++++-- src/lib/tvgShapePath.h | 82 ++++++++++++--------------------- test/makefile | 1 + test/testPath.cpp | 116 +++++++++++++++++++++++++++++++++++++++++------ 7 files changed, 156 insertions(+), 70 deletions(-) diff --git a/.gitignore b/.gitignore index bbd3f8e..ddc6523 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ testShape testMultiShapes testMergeShapes testBoundary +testPath diff --git a/inc/tizenvg.h b/inc/tizenvg.h index c53a5dc..89db3f5 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -121,6 +121,7 @@ public: int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; + int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; int fill(size_t r, size_t g, size_t b, size_t a) noexcept; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 2653d3a..c3f0c56 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "tizenvg.h" #include "tvgRenderCommon.h" diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index a6e4511..0c01c0f 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -109,7 +109,9 @@ int ShapeNode::clear() noexcept auto impl = pImpl.get(); assert(impl); - return impl->path->clear(); + impl->path->clear(); + + return 0; } @@ -135,6 +137,20 @@ int ShapeNode::pathCoords(const Point** pts) const noexcept } +int ShapeNode::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept +{ + if (cmdCnt < 0 || ptsCnt < 0) return -1; + assert(cmds && pts); + + auto impl = pImpl.get(); + assert(impl); + + impl->path->append(cmds, cmdCnt, pts, ptsCnt); + + return 0; +} + + int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); @@ -143,7 +159,7 @@ int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) no auto halfKappaW = radiusW * PATH_KAPPA; auto halfKappaH = radiusH * PATH_KAPPA; - impl->path->reserve(6, 13); + impl->path->grow(6, 13); impl->path->moveTo(cx, cy - radiusH); impl->path->cubicTo(cx + halfKappaW, cy - radiusH, cx + radiusW, cy - halfKappaH, cx + radiusW, cy); impl->path->cubicTo(cx + radiusW, cy + halfKappaH, cx + halfKappaW, cy + radiusH, cx, cy + radiusH); @@ -166,7 +182,7 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius //rectangle if (cornerRadius == 0) { - impl->path->reserve(5, 4); + impl->path->grow(5, 4); impl->path->moveTo(x, y); impl->path->lineTo(x + w, y); impl->path->lineTo(x + w, y + h); @@ -177,7 +193,7 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius, cornerRadius); } else { auto halfKappa = cornerRadius * 0.5; - impl->path->reserve(10, 17); + impl->path->grow(10, 17); impl->path->moveTo(x + cornerRadius, y); impl->path->lineTo(x + w - cornerRadius, y); impl->path->cubicTo(x + w - cornerRadius + halfKappa, y, x + w, y + cornerRadius - halfKappa, x + w, y + cornerRadius); diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 6fda0f0..f4fee18 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -40,65 +40,68 @@ struct ShapePath if (pts) delete(pts); } - int reserveCmd(size_t cmdCnt) + void reserveCmd(size_t cmdCnt) { - if (cmdCnt > reservedCmdCnt) { - reservedCmdCnt = cmdCnt; - cmds = static_cast(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt)); - assert(cmds); - } - return 0; + if (cmdCnt <= reservedCmdCnt) return; + reservedCmdCnt = cmdCnt; + cmds = static_cast(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt)); + assert(cmds); } - int reservePts(size_t ptsCnt) + void reservePts(size_t ptsCnt) { - if (ptsCnt > reservedPtsCnt) { - reservedPtsCnt = ptsCnt; - pts = static_cast(realloc(pts, sizeof(Point) * reservedPtsCnt)); - assert(pts); - } - return 0; + if (ptsCnt <= reservedPtsCnt) return; + reservedPtsCnt = ptsCnt; + pts = static_cast(realloc(pts, sizeof(Point) * reservedPtsCnt)); + assert(pts); } - int reserve(size_t cmdCnt, size_t ptsCnt) + void reserve(size_t cmdCnt, size_t ptsCnt) { reserveCmd(cmdCnt); reservePts(ptsCnt); + } - return 0; + void grow(size_t cmdCnt, size_t ptsCnt) + { + reserveCmd(this->cmdCnt + cmdCnt); + reservePts(this->ptsCnt + ptsCnt); } - int clear() + void clear() { cmdCnt = 0; ptsCnt = 0; + } - return 0; + void append(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) + { + grow(cmdCnt, ptsCnt); + memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt); + memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt); + this->cmdCnt += cmdCnt; + this->ptsCnt += ptsCnt; } - int moveTo(float x, float y) + void moveTo(float x, float y) { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2); cmds[cmdCnt++] = PathCommand::MoveTo; pts[ptsCnt++] = {x, y}; - - return 0; } - int lineTo(float x, float y) + void lineTo(float x, float y) { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2); cmds[cmdCnt++] = PathCommand::LineTo; pts[ptsCnt++] = {x, y}; - - return 0; } - int cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) + void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2); @@ -107,39 +110,12 @@ struct ShapePath pts[ptsCnt++] = {cx1, cy1}; pts[ptsCnt++] = {cx2, cy2}; pts[ptsCnt++] = {x, y}; - - return 0; } - - int close() + void close() { if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); cmds[cmdCnt++] = PathCommand::Close; - - return 0; - } - - int bounds(float& x, float& y, float& w, float& h) - { - if (ptsCnt == 0) return -1; - - Point min = { pts[0].x, pts[0].y }; - Point max = { pts[0].x, pts[0].y }; - - for(size_t i = 1; i <= ptsCnt; ++i) { - if (pts[i].x < min.x) min.x = pts[i].x; - if (pts[i].y < min.y) min.y = pts[i].y; - if (pts[i].x > max.x) max.x = pts[i].x; - if (pts[i].y > max.y) max.y = pts[i].y; - } - - x = min.x; - y = min.y; - w = max.x - min.x; - h = max.y - min.y; - - return 0; } }; diff --git a/test/makefile b/test/makefile index 1bab747..e213907 100644 --- a/test/makefile +++ b/test/makefile @@ -3,3 +3,4 @@ all: gcc -o testMultiShapes testMultiShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testMergeShapes testMergeShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testPath testPath.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testPath.cpp b/test/testPath.cpp index e260682..a75c7f7 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -1,4 +1,5 @@ #include +#include using namespace std; @@ -7,7 +8,7 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; -int main(int argc, char **argv) +void tvgtest() { //Initialize TizenVG Engine tvg::Engine::init(); @@ -15,25 +16,114 @@ int main(int argc, char **argv) //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - //Prepare Path - auto path = tvg::Path::gen(); - path.reserve(cmdCnt, ptCnt); //command count, points count - path.moveTo(...); - path.lineTo(...); - path.cubicTo(...); - path.close(); + /* Star */ + + //Prepare Path Commands + tvg::PathCommand cmds[11]; + cmds[0] = tvg::PathCommand::MoveTo; + cmds[1] = tvg::PathCommand::LineTo; + cmds[2] = tvg::PathCommand::LineTo; + cmds[3] = tvg::PathCommand::LineTo; + cmds[4] = tvg::PathCommand::LineTo; + cmds[5] = tvg::PathCommand::LineTo; + cmds[6] = tvg::PathCommand::LineTo; + cmds[7] = tvg::PathCommand::LineTo; + cmds[8] = tvg::PathCommand::LineTo; + cmds[9] = tvg::PathCommand::LineTo; + cmds[10] = tvg::PathCommand::Close; + + //Prepare Path Points + tvg::Point pts[10]; + pts[0] = {199, 34}; //MoveTo + pts[1] = {253, 143}; //LineTo + pts[2] = {374, 160}; //LineTo + pts[3] = {287, 244}; //LineTo + pts[4] = {307, 365}; //LineTo + pts[5] = {199, 309}; //LineTo + pts[6] = {97, 365}; //LineTo + pts[7] = {112, 245}; //LineTo + pts[8] = {26, 161}; //LineTo + pts[9] = {146, 143}; //LineTo - //Prepare a Shape auto shape1 = tvg::ShapeNode::gen(); - shape1->path(move(path)); //migrate owner otherwise, - shape1->path(path.get()); //copy raw data directly for performance + shape1->appendPath(cmds, 11, pts, 10); //copy path data shape1->fill(0, 255, 0, 255); - - //Draw the Shape onto the Canvas canvas->push(move(shape1)); + + + /* Circle */ + auto cx = 550.0f; + auto cy = 550.0f; + auto radius = 125.0f; + auto halfRadius = radius * 0.552284f; + + //Prepare Path Commands + tvg::PathCommand cmds2[6]; + cmds2[0] = tvg::PathCommand::MoveTo; + cmds2[1] = tvg::PathCommand::CubicTo; + cmds2[2] = tvg::PathCommand::CubicTo; + cmds2[3] = tvg::PathCommand::CubicTo; + cmds2[4] = tvg::PathCommand::CubicTo; + cmds2[5] = tvg::PathCommand::Close; + + //Prepare Path Points + tvg::Point pts2[13]; + pts2[0] = {cx, cy - radius}; //MoveTo + //CubicTo 1 + pts2[1] = {cx + halfRadius, cy - radius}; //Ctrl1 + pts2[2] = {cx + radius, cy - halfRadius}; //Ctrl2 + pts2[3] = {cx + radius, cy}; //To + //CubicTo 2 + pts2[4] = {cx + radius, cy + halfRadius}; //Ctrl1 + pts2[5] = {cx + halfRadius, cy + radius}; //Ctrl2 + pts2[6] = {cx, cy+ radius}; //To + //CubicTo 3 + pts2[7] = {cx - halfRadius, cy + radius}; //Ctrl1 + pts2[8] = {cx - radius, cy + halfRadius}; //Ctrl2 + pts2[9] = {cx - radius, cy}; //To + //CubicTo 4 + pts2[10] = {cx - radius, cy - halfRadius}; //Ctrl1 + pts2[11] = {cx - halfRadius, cy - radius}; //Ctrl2 + pts2[12] = {cx, cy - radius}; //To + + auto shape2 = tvg::ShapeNode::gen(); + shape2->appendPath(cmds2, 6, pts2, 13); //copy path data + shape2->fill(255, 255, 0, 255); + canvas->push(move(shape2)); + canvas->draw(); canvas->sync(); //Terminate TizenVG Engine tvg::Engine::term(); } + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} -- 2.7.4 From 308456ebade78905cd2ad6e9e3f8a5770475d523 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 18:38:34 +0900 Subject: [PATCH 03/16] common shape: remove unnecessary log Change-Id: Ie85153afdc01270ed282d9ff87607ee1a882be31 --- src/lib/tvgShapeNode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 0c01c0f..12ce6de 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -75,7 +75,6 @@ ShapeNode :: ShapeNode() : pImpl(make_unique()) ShapeNode :: ~ShapeNode() { - cout << "ShapeNode(" << this << ") destroyed!" << endl; } -- 2.7.4 From 700a44c623f9ff663d7b6488dbe831fe672ca7be Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 19:11:04 +0900 Subject: [PATCH 04/16] common shape: added path commands interfaces for user convenient. +lineTo() +moveTo() +cubicTo() +close() These interfaces might not perfect optmizied, but you can build path commands easier than manual data set. Change-Id: Icb934ca256d3107ca0c938d28015d767fb93355e --- .gitignore | 1 + inc/tizenvg.h | 5 +++ src/lib/sw_engine/tvgSwRle.cpp | 2 +- src/lib/tvgShapeNode.cpp | 45 +++++++++++++++++++++ src/lib/tvgShapePath.h | 9 +---- test/makefile | 1 + test/testPath2.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 test/testPath2.cpp diff --git a/.gitignore b/.gitignore index ddc6523..8e92d13 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ testMultiShapes testMergeShapes testBoundary testPath +testPath2 diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 89db3f5..83e5f1d 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -119,6 +119,11 @@ public: int update(RenderMethod* engine) noexcept override; int clear() noexcept; + int moveTo(float x, float y) noexcept; + int lineTo(float x, float y) noexcept; + int cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept; + int close() noexcept; + int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 02870c3..5166de8 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -637,7 +637,7 @@ static bool _decomposeOutline(RleWorker& rw) } } - //Close the contour with a line segment? + //FIXME: Close the contour with a line segment? //_lineTo(rw, UPSCALE(outline->pts[first])); close: first = last + 1; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 12ce6de..b8397df 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -144,12 +144,57 @@ int ShapeNode::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* p auto impl = pImpl.get(); assert(impl); + impl->path->grow(cmdCnt, ptsCnt); impl->path->append(cmds, cmdCnt, pts, ptsCnt); return 0; } +int ShapeNode::moveTo(float x, float y) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->path->moveTo(x, y); + + return 0; +} + + +int ShapeNode::lineTo(float x, float y) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->path->lineTo(x, y); + + return 0; +} + + +int ShapeNode::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); + + return 0; +} + + +int ShapeNode::close() noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + impl->path->close(); + + return 0; +} + + int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index f4fee18..2849099 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -56,12 +56,6 @@ struct ShapePath assert(pts); } - void reserve(size_t cmdCnt, size_t ptsCnt) - { - reserveCmd(cmdCnt); - reservePts(ptsCnt); - } - void grow(size_t cmdCnt, size_t ptsCnt) { reserveCmd(this->cmdCnt + cmdCnt); @@ -76,7 +70,6 @@ struct ShapePath void append(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) { - grow(cmdCnt, ptsCnt); memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt); memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt); this->cmdCnt += cmdCnt; @@ -114,6 +107,8 @@ struct ShapePath void close() { + if (cmdCnt > 0 && cmds[cmdCnt - 1] == PathCommand::Close) return; + if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); cmds[cmdCnt++] = PathCommand::Close; } diff --git a/test/makefile b/test/makefile index e213907..1471ecd 100644 --- a/test/makefile +++ b/test/makefile @@ -4,3 +4,4 @@ all: gcc -o testMergeShapes testMergeShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testPath testPath.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testPath2 testPath2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testPath2.cpp b/test/testPath2.cpp new file mode 100644 index 0000000..3c6738a --- /dev/null +++ b/test/testPath2.cpp @@ -0,0 +1,89 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + //Star + auto shape1 = tvg::ShapeNode::gen(); + + //Appends Paths + shape1->moveTo(199, 34); + shape1->lineTo(253, 143); + shape1->lineTo(374, 160); + shape1->lineTo(287, 244); + shape1->lineTo(307, 365); + shape1->lineTo(199, 309); + shape1->lineTo(97, 365); + shape1->lineTo(112, 245); + shape1->lineTo(26, 161); + shape1->lineTo(146, 143); + shape1->close(); + shape1->fill(0, 0, 255, 255); + canvas->push(move(shape1)); + + //Circle + auto shape2 = tvg::ShapeNode::gen(); + + auto cx = 550.0f; + auto cy = 550.0f; + auto radius = 125.0f; + auto halfRadius = radius * 0.552284f; + + //Append Paths + shape2->moveTo(cx, cy - radius); + shape2->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy); + shape2->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius); + shape2->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); + shape2->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); + shape2->fill(255, 0, 0, 255); + canvas->push(move(shape2)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} -- 2.7.4 From 14efeb4f0b84858a3a8c1f21c42868ed6bd7cee3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 23:40:35 +0900 Subject: [PATCH 05/16] test: updated comments Change-Id: I92fccb5a9de088f837a768a2f1d60ac94eac9410 --- test/testMergeShapes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index b37440b..268e958 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -16,7 +16,7 @@ void tvgtest() //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - //Prepare a Shape (Rectangle + Rectangle + Circle) + //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::ShapeNode::gen(); shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius shape1->appendRect(100, 100, 300, 300, 100); //x, y, w, h, cornerRadius -- 2.7.4 From 2f174560ebe96ed6bbf779361d9301412cb920b7 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 1 May 2020 12:46:54 +0900 Subject: [PATCH 06/16] test: rename testPath to testPathCopy Change-Id: I8cf2a26437a804d2cd061d61d3a99b3c6f3aa0e6 --- .gitignore | 2 +- test/makefile | 2 +- test/testPath.cpp | 88 ++++++++++------------------------ test/testPath2.cpp | 89 ---------------------------------- test/testPathCopy.cpp | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 155 deletions(-) delete mode 100644 test/testPath2.cpp create mode 100644 test/testPathCopy.cpp diff --git a/.gitignore b/.gitignore index 8e92d13..2c0e514 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ testMultiShapes testMergeShapes testBoundary testPath -testPath2 +testPathCopy diff --git a/test/makefile b/test/makefile index 1471ecd..e28d76b 100644 --- a/test/makefile +++ b/test/makefile @@ -4,4 +4,4 @@ all: gcc -o testMergeShapes testMergeShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testPath testPath.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testPath2 testPath2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testPathCopy testPathCopy.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testPath.cpp b/test/testPath.cpp index a75c7f7..3c6738a 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -16,79 +16,39 @@ void tvgtest() //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - /* Star */ - - //Prepare Path Commands - tvg::PathCommand cmds[11]; - cmds[0] = tvg::PathCommand::MoveTo; - cmds[1] = tvg::PathCommand::LineTo; - cmds[2] = tvg::PathCommand::LineTo; - cmds[3] = tvg::PathCommand::LineTo; - cmds[4] = tvg::PathCommand::LineTo; - cmds[5] = tvg::PathCommand::LineTo; - cmds[6] = tvg::PathCommand::LineTo; - cmds[7] = tvg::PathCommand::LineTo; - cmds[8] = tvg::PathCommand::LineTo; - cmds[9] = tvg::PathCommand::LineTo; - cmds[10] = tvg::PathCommand::Close; - - //Prepare Path Points - tvg::Point pts[10]; - pts[0] = {199, 34}; //MoveTo - pts[1] = {253, 143}; //LineTo - pts[2] = {374, 160}; //LineTo - pts[3] = {287, 244}; //LineTo - pts[4] = {307, 365}; //LineTo - pts[5] = {199, 309}; //LineTo - pts[6] = {97, 365}; //LineTo - pts[7] = {112, 245}; //LineTo - pts[8] = {26, 161}; //LineTo - pts[9] = {146, 143}; //LineTo - + //Star auto shape1 = tvg::ShapeNode::gen(); - shape1->appendPath(cmds, 11, pts, 10); //copy path data - shape1->fill(0, 255, 0, 255); + + //Appends Paths + shape1->moveTo(199, 34); + shape1->lineTo(253, 143); + shape1->lineTo(374, 160); + shape1->lineTo(287, 244); + shape1->lineTo(307, 365); + shape1->lineTo(199, 309); + shape1->lineTo(97, 365); + shape1->lineTo(112, 245); + shape1->lineTo(26, 161); + shape1->lineTo(146, 143); + shape1->close(); + shape1->fill(0, 0, 255, 255); canvas->push(move(shape1)); + //Circle + auto shape2 = tvg::ShapeNode::gen(); - /* Circle */ auto cx = 550.0f; auto cy = 550.0f; auto radius = 125.0f; auto halfRadius = radius * 0.552284f; - //Prepare Path Commands - tvg::PathCommand cmds2[6]; - cmds2[0] = tvg::PathCommand::MoveTo; - cmds2[1] = tvg::PathCommand::CubicTo; - cmds2[2] = tvg::PathCommand::CubicTo; - cmds2[3] = tvg::PathCommand::CubicTo; - cmds2[4] = tvg::PathCommand::CubicTo; - cmds2[5] = tvg::PathCommand::Close; - - //Prepare Path Points - tvg::Point pts2[13]; - pts2[0] = {cx, cy - radius}; //MoveTo - //CubicTo 1 - pts2[1] = {cx + halfRadius, cy - radius}; //Ctrl1 - pts2[2] = {cx + radius, cy - halfRadius}; //Ctrl2 - pts2[3] = {cx + radius, cy}; //To - //CubicTo 2 - pts2[4] = {cx + radius, cy + halfRadius}; //Ctrl1 - pts2[5] = {cx + halfRadius, cy + radius}; //Ctrl2 - pts2[6] = {cx, cy+ radius}; //To - //CubicTo 3 - pts2[7] = {cx - halfRadius, cy + radius}; //Ctrl1 - pts2[8] = {cx - radius, cy + halfRadius}; //Ctrl2 - pts2[9] = {cx - radius, cy}; //To - //CubicTo 4 - pts2[10] = {cx - radius, cy - halfRadius}; //Ctrl1 - pts2[11] = {cx - halfRadius, cy - radius}; //Ctrl2 - pts2[12] = {cx, cy - radius}; //To - - auto shape2 = tvg::ShapeNode::gen(); - shape2->appendPath(cmds2, 6, pts2, 13); //copy path data - shape2->fill(255, 255, 0, 255); + //Append Paths + shape2->moveTo(cx, cy - radius); + shape2->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy); + shape2->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius); + shape2->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); + shape2->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); + shape2->fill(255, 0, 0, 255); canvas->push(move(shape2)); canvas->draw(); diff --git a/test/testPath2.cpp b/test/testPath2.cpp deleted file mode 100644 index 3c6738a..0000000 --- a/test/testPath2.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() -{ - //Initialize TizenVG Engine - tvg::Engine::init(); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - - //Star - auto shape1 = tvg::ShapeNode::gen(); - - //Appends Paths - shape1->moveTo(199, 34); - shape1->lineTo(253, 143); - shape1->lineTo(374, 160); - shape1->lineTo(287, 244); - shape1->lineTo(307, 365); - shape1->lineTo(199, 309); - shape1->lineTo(97, 365); - shape1->lineTo(112, 245); - shape1->lineTo(26, 161); - shape1->lineTo(146, 143); - shape1->close(); - shape1->fill(0, 0, 255, 255); - canvas->push(move(shape1)); - - //Circle - auto shape2 = tvg::ShapeNode::gen(); - - auto cx = 550.0f; - auto cy = 550.0f; - auto radius = 125.0f; - auto halfRadius = radius * 0.552284f; - - //Append Paths - shape2->moveTo(cx, cy - radius); - shape2->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy); - shape2->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius); - shape2->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); - shape2->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); - shape2->fill(255, 0, 0, 255); - canvas->push(move(shape2)); - - canvas->draw(); - canvas->sync(); - - //Terminate TizenVG Engine - tvg::Engine::term(); -} - -void -win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} - -int main(int argc, char **argv) -{ - tvgtest(); - - //Show the result using EFL... - elm_init(argc, argv); - - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); - - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); - - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - - elm_run(); - elm_shutdown(); -} diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp new file mode 100644 index 0000000..a75c7f7 --- /dev/null +++ b/test/testPathCopy.cpp @@ -0,0 +1,129 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + + /* Star */ + + //Prepare Path Commands + tvg::PathCommand cmds[11]; + cmds[0] = tvg::PathCommand::MoveTo; + cmds[1] = tvg::PathCommand::LineTo; + cmds[2] = tvg::PathCommand::LineTo; + cmds[3] = tvg::PathCommand::LineTo; + cmds[4] = tvg::PathCommand::LineTo; + cmds[5] = tvg::PathCommand::LineTo; + cmds[6] = tvg::PathCommand::LineTo; + cmds[7] = tvg::PathCommand::LineTo; + cmds[8] = tvg::PathCommand::LineTo; + cmds[9] = tvg::PathCommand::LineTo; + cmds[10] = tvg::PathCommand::Close; + + //Prepare Path Points + tvg::Point pts[10]; + pts[0] = {199, 34}; //MoveTo + pts[1] = {253, 143}; //LineTo + pts[2] = {374, 160}; //LineTo + pts[3] = {287, 244}; //LineTo + pts[4] = {307, 365}; //LineTo + pts[5] = {199, 309}; //LineTo + pts[6] = {97, 365}; //LineTo + pts[7] = {112, 245}; //LineTo + pts[8] = {26, 161}; //LineTo + pts[9] = {146, 143}; //LineTo + + auto shape1 = tvg::ShapeNode::gen(); + shape1->appendPath(cmds, 11, pts, 10); //copy path data + shape1->fill(0, 255, 0, 255); + canvas->push(move(shape1)); + + + /* Circle */ + auto cx = 550.0f; + auto cy = 550.0f; + auto radius = 125.0f; + auto halfRadius = radius * 0.552284f; + + //Prepare Path Commands + tvg::PathCommand cmds2[6]; + cmds2[0] = tvg::PathCommand::MoveTo; + cmds2[1] = tvg::PathCommand::CubicTo; + cmds2[2] = tvg::PathCommand::CubicTo; + cmds2[3] = tvg::PathCommand::CubicTo; + cmds2[4] = tvg::PathCommand::CubicTo; + cmds2[5] = tvg::PathCommand::Close; + + //Prepare Path Points + tvg::Point pts2[13]; + pts2[0] = {cx, cy - radius}; //MoveTo + //CubicTo 1 + pts2[1] = {cx + halfRadius, cy - radius}; //Ctrl1 + pts2[2] = {cx + radius, cy - halfRadius}; //Ctrl2 + pts2[3] = {cx + radius, cy}; //To + //CubicTo 2 + pts2[4] = {cx + radius, cy + halfRadius}; //Ctrl1 + pts2[5] = {cx + halfRadius, cy + radius}; //Ctrl2 + pts2[6] = {cx, cy+ radius}; //To + //CubicTo 3 + pts2[7] = {cx - halfRadius, cy + radius}; //Ctrl1 + pts2[8] = {cx - radius, cy + halfRadius}; //Ctrl2 + pts2[9] = {cx - radius, cy}; //To + //CubicTo 4 + pts2[10] = {cx - radius, cy - halfRadius}; //Ctrl1 + pts2[11] = {cx - halfRadius, cy - radius}; //Ctrl2 + pts2[12] = {cx, cy - radius}; //To + + auto shape2 = tvg::ShapeNode::gen(); + shape2->appendPath(cmds2, 6, pts2, 13); //copy path data + shape2->fill(255, 255, 0, 255); + canvas->push(move(shape2)); + + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} -- 2.7.4 From 74d2f275e74c4aa4bf3b9b68f297c2d0f95d8c80 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 1 May 2020 13:59:02 +0900 Subject: [PATCH 07/16] sw_engine: support color blending this contains testBlending as well Change-Id: Ia0aadea804a973cfe8ec981ed1b21c1b44512ef2 --- .gitignore | 1 + inc/tizenvg.h | 4 +- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRaster.cpp | 58 +++++++++++++++++++--- src/lib/sw_engine/tvgSwRenderer.cpp | 31 ++++++++---- src/lib/sw_engine/tvgSwRenderer.h | 3 +- src/lib/tvgRenderCommon.h | 2 +- src/lib/tvgSwCanvas.cpp | 10 ++-- test/makefile | 1 + test/testBlending.cpp | 97 +++++++++++++++++++++++++++++++++++++ test/testBoundary.cpp | 3 +- test/testMergeShapes.cpp | 3 +- test/testMultiShapes.cpp | 3 +- test/testPath.cpp | 3 +- test/testPathCopy.cpp | 3 +- test/testShape.cpp | 3 +- 16 files changed, 194 insertions(+), 33 deletions(-) create mode 100644 test/testBlending.cpp diff --git a/.gitignore b/.gitignore index 2c0e514..c26c55d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ testMergeShapes testBoundary testPath testPathCopy +testBlending diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 83e5f1d..8708695 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -179,9 +179,9 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - int target(uint32_t* buffer, size_t stride, size_t height) noexcept; + int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; int sync() noexcept override; - static std::unique_ptr gen(uint32_t* buffer = nullptr, size_t stride = 0, size_t height = 0) noexcept; + static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(SwCanvas); }; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 012f968..4b31bcd 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -99,6 +99,6 @@ bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip); bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); -bool rasterShape(Surface& surface, SwShape& sdata, size_t color); +bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); #endif /* _TVG_SW_COMMON_H_ */ diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index a71c443..29350db 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -20,20 +20,66 @@ #include "tvgSwCommon.h" -bool rasterShape(Surface& surface, SwShape& sdata, size_t color) +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static inline size_t COLOR_ALPHA_BLEND(size_t color, size_t alpha) +{ + return (((((color >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + + ((((color & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); +} + + +static inline size_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (a << 24 | r << 16 | g << 8 | b); +} + + +static void +_drawTranslucentSpan(uint32_t* dst, size_t len, size_t color, size_t alpha) +{ + //OPTIMIZE ME: SIMD + auto ialpha = 255 - alpha; + for (size_t i = 0; i < len; ++i) { + dst[i] = color + COLOR_ALPHA_BLEND(dst[i], ialpha); + } +} + + +static void +_drawSolidSpan(uint32_t* dst, size_t len, size_t color) +{ + //OPTIMIZE ME: SIMD + for (size_t i = 0; i < len; ++i) { + dst[i] = color; + } +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { SwRleData* rle = sdata.rle; if (!rle) return false; - auto stride = surface.stride; auto span = rle->spans; + auto stride = surface.stride; + auto color = COLOR_ARGB_JOIN(r, g, b, a); for (size_t i = 0; i < rle->size; ++i) { assert(span); -// printf("raster y(%d) x(%d) len(%d)\n", span->y, span->x, span->len); - for (auto j = 0; j < span->len; ++j) { - surface.buffer[span->y * stride + span->x + j] = color; - } + + auto dst = &surface.buffer[span->y * stride + span->x]; + assert(dst); + + if (a == 255) _drawSolidSpan(dst, span->len, color); + else _drawTranslucentSpan(dst, span->len, color, a); + ++span; } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index ae43735..983a1ca 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -26,22 +26,33 @@ static RenderInitializer renderInit; -static inline size_t COLOR(uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - return (a << 24 | r << 16 | g << 8 | b); -} - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t height) +bool SwRenderer::clear() +{ + if (!surface.buffer) return false; + + assert(surface.stride > 0 && surface.w > 0 && surface.h > 0); + + //OPTIMIZE ME: SIMD! + for (size_t i = 0; i < surface.h; i++) { + for (size_t j = 0; j < surface.w; j++) + surface.buffer[surface.stride * i + j] = 0xff000000; //Solid Black + } + + return true; +} + +bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) { - assert(buffer && stride > 0 && height > 0); + assert(buffer && stride > 0 && w > 0 && h > 0); surface.buffer = buffer; surface.stride = stride; - surface.height = height; + surface.w = w; + surface.h = h; return true; } @@ -57,7 +68,7 @@ bool SwRenderer::render(const ShapeNode& shape, void *data) shape.fill(&r, &g, &b, &a); //TODO: Threading - return rasterShape(surface, *sdata, COLOR(r, g, b, a)); + return rasterShape(surface, *sdata, r, g, b, a); } @@ -92,7 +103,7 @@ void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) if (!shapeGenOutline(shape, *sdata)) return sdata; if (!shapeTransformOutline(shape, *sdata)) return sdata; - SwSize clip = {static_cast(surface.stride), static_cast(surface.height)}; + SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; if (!shapeGenRle(shape, *sdata, clip)) return sdata; } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index f8ce1d4..5de6c12 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -25,7 +25,8 @@ public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; bool dispose(const ShapeNode& shape, void *data) override; bool render(const ShapeNode& shape, void *data) override; - bool target(uint32_t* buffer, size_t stride, size_t height); + bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); + bool clear(); size_t ref() override; size_t unref() override; diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index acdfc2f..ccbc415 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -25,7 +25,7 @@ struct Surface //TODO: Union for multiple types uint32_t* buffer; size_t stride; - size_t height; + size_t w, h; }; class RenderMethod diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 04902fc..668c377 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,12 +45,13 @@ SwCanvas::~SwCanvas() } -int SwCanvas::target(uint32_t* buffer, size_t stride, size_t height) noexcept +int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(engine()); assert(renderer); - if (!renderer->target(buffer, stride, height)) return -1; + if (!renderer->target(buffer, stride, w, h)) return -1; + if (!renderer->clear()) return -1; return 0; } @@ -62,14 +63,11 @@ int SwCanvas::sync() noexcept } -unique_ptr SwCanvas::gen(uint32_t* buffer, size_t stride, size_t height) noexcept +unique_ptr SwCanvas::gen() noexcept { auto canvas = unique_ptr(new SwCanvas); assert(canvas); - int ret = canvas.get()->target(buffer, stride, height); - if (ret > 0) return nullptr; - return canvas; } diff --git a/test/makefile b/test/makefile index e28d76b..f455654 100644 --- a/test/makefile +++ b/test/makefile @@ -5,3 +5,4 @@ all: gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testPath testPath.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testPathCopy testPathCopy.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testBlending testBlending.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testBlending.cpp b/test/testBlending.cpp new file mode 100644 index 0000000..ef142aa --- /dev/null +++ b/test/testBlending.cpp @@ -0,0 +1,97 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + canvas->reserve(5); + + //Prepare Round Rectangle + auto shape1 = tvg::ShapeNode::gen(); + shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->fill(0, 255, 0, 255); //r, g, b, a + canvas->push(move(shape1)); + + //Prepare Circle + auto shape2 = tvg::ShapeNode::gen(); + shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH + shape2->fill(170, 170, 0, 170); //r, g, b, a + canvas->push(move(shape2)); + + //Prepare Ellipse + auto shape3 = tvg::ShapeNode::gen(); + shape3->appendCircle(400, 400, 250, 100); //cx, cy, radiusW, radiusH + shape3->fill(100, 100, 100, 100); //r, g, b, a + canvas->push(move(shape3)); + + //Prepare Star + auto shape4 = tvg::ShapeNode::gen(); + shape4->moveTo(199, 234); + shape4->lineTo(253, 343); + shape4->lineTo(374, 360); + shape4->lineTo(287, 444); + shape4->lineTo(307, 565); + shape4->lineTo(199, 509); + shape4->lineTo(97, 565); + shape4->lineTo(112, 445); + shape4->lineTo(26, 361); + shape4->lineTo(146, 343); + shape4->close(); + shape4->fill(200, 0, 200, 200); + canvas->push(move(shape4)); + + //Prepare Opaque Ellipse + auto shape5 = tvg::ShapeNode::gen(); + shape5->appendCircle(600, 650, 200, 150); + shape5->fill(0, 0, 255, 255); + canvas->push(move(shape5)); + + //Draw the Shapes onto the Canvas + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 473fd59..7d305be 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(5); //reserve 5 shape nodes (optional) //Prepare Shape1 diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index 268e958..27ef0c5 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::ShapeNode::gen(); diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 6fc0469..d53e9fc 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle diff --git a/test/testPath.cpp b/test/testPath.cpp index 3c6738a..1ae897d 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Star auto shape1 = tvg::ShapeNode::gen(); diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index a75c7f7..e555226 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); /* Star */ diff --git a/test/testShape.cpp b/test/testShape.cpp index b7fca2f..4386637 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -14,7 +14,8 @@ void tvgtest() tvg::Engine::init(); //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); -- 2.7.4 From 11e070d1672d6ff88f47ee365d27b296c674cf09 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 1 May 2020 17:15:31 +0900 Subject: [PATCH 08/16] sw_engine: support anti-aliasing Change-Id: I9b79c8b4022ddf2ae4fe980f480ba3ec140750d3 --- src/lib/sw_engine/tvgSwRaster.cpp | 35 ++++++++++++++++++++++++++--------- src/lib/sw_engine/tvgSwRle.cpp | 4 ++-- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 29350db..0b813fd 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -24,6 +24,12 @@ /* Internal Class Implementation */ /************************************************************************/ +static inline size_t COLOR_ALPHA(size_t color) +{ + return (color >> 24) & 0xff; +} + + static inline size_t COLOR_ALPHA_BLEND(size_t color, size_t alpha) { return (((((color >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + @@ -33,15 +39,18 @@ static inline size_t COLOR_ALPHA_BLEND(size_t color, size_t alpha) static inline size_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return (a << 24 | r << 16 | g << 8 | b); + return (a << 24 | r << 16 | g << 8 | b); } static void -_drawTranslucentSpan(uint32_t* dst, size_t len, size_t color, size_t alpha) +_rasterTranslucent(uint32_t* dst, size_t len, size_t color, size_t cov) { //OPTIMIZE ME: SIMD - auto ialpha = 255 - alpha; + + if (cov < 255) color = COLOR_ALPHA_BLEND(color, cov); + auto ialpha = 255 - COLOR_ALPHA(color); + for (size_t i = 0; i < len; ++i) { dst[i] = color + COLOR_ALPHA_BLEND(dst[i], ialpha); } @@ -49,11 +58,20 @@ _drawTranslucentSpan(uint32_t* dst, size_t len, size_t color, size_t alpha) static void -_drawSolidSpan(uint32_t* dst, size_t len, size_t color) +_rasterSolid(uint32_t* dst, size_t len, size_t color, size_t cov) { //OPTIMIZE ME: SIMD - for (size_t i = 0; i < len; ++i) { - dst[i] = color; + + //Fully Opaque + if (cov == 255) { + for (size_t i = 0; i < len; ++i) { + dst[i] = color; + } + } else { + auto ialpha = 255 - cov; + for (size_t i = 0; i < len; ++i) { + dst[i] = COLOR_ALPHA_BLEND(color, cov) + COLOR_ALPHA_BLEND(dst[i], ialpha); + } } } @@ -75,10 +93,9 @@ bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t assert(span); auto dst = &surface.buffer[span->y * stride + span->x]; - assert(dst); - if (a == 255) _drawSolidSpan(dst, span->len, color); - else _drawTranslucentSpan(dst, span->len, color, a); + if (a == 255) _rasterSolid(dst, span->len, color, span->coverage); + else _rasterTranslucent(dst, span->len, color, span->coverage); ++span; } diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 5166de8..f915a5d 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -434,8 +434,8 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) /* These macros speed up repetitive divisions by replacing them with multiplications and right shifts. */ - auto dx_r = (ULONG_MAX >> PIXEL_BITS) / (diff.x); - auto dy_r = (ULONG_MAX >> PIXEL_BITS) / (diff.y); + auto dx_r = static_cast(ULONG_MAX >> PIXEL_BITS) / (diff.x); + auto dy_r = static_cast(ULONG_MAX >> PIXEL_BITS) / (diff.y); /* The fundamental value `prod' determines which side and the */ /* exact coordinate where the line exits current cell. It is */ -- 2.7.4 From c923d881aa8ecdb04d5f296bc3e6ea5d4dcff289 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 10:55:33 +0900 Subject: [PATCH 09/16] test: added testUpdate this shows a moving shape: how to update canvas every frames. Change-Id: I373e39757f4511d4e676f36d76e468d03b185a0c --- .gitignore | 1 + inc/tizenvg.h | 1 + src/lib/tvgSwCanvas.cpp | 11 ++++++ test/makefile | 1 + test/testUpdate.cpp | 103 ++++++++++++++++++++++++++++++++---------------- 5 files changed, 83 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index c26c55d..06f9099 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ testBoundary testPath testPathCopy testBlending +testUpdate diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 8708695..f325276 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -179,6 +179,7 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); + int clear() noexcept override; int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; int sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 668c377..cc26cbd 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,6 +45,17 @@ SwCanvas::~SwCanvas() } +int SwCanvas::clear() noexcept +{ + auto renderer = dynamic_cast(engine()); + assert(renderer); + + if (!renderer->clear()) return -1; + + return Canvas::clear(); +} + + int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(engine()); diff --git a/test/makefile b/test/makefile index f455654..e12fb31 100644 --- a/test/makefile +++ b/test/makefile @@ -6,3 +6,4 @@ all: gcc -o testPath testPath.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testPathCopy testPathCopy.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testBlending testBlending.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testUpdate testUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 3a81289..c4250fb 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -1,4 +1,5 @@ #include +#include using namespace std; @@ -6,50 +7,84 @@ using namespace std; #define HEIGHT 800 static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; -int main(int argc, char **argv) +void tvgtest() { - //Initialize TizenVG Engine - tvg::Engine::init(); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape + auto shape = tvg::ShapeNode::gen(); + shape->appendRect(-100, -100, 200, 200, 0); + shape->fill(255, 255, 255, 255); + canvas->push(move(shape)); + + //Draw first frame + canvas->draw(); + canvas->sync(); +} - //Create a Scene - auto scene = tvg::SceneNode::gen(); +void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + //Explicitly clear all retained paint nodes. + canvas->clear(); + + //Shape + auto shape = tvg::ShapeNode::gen(); + shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + shape->fill(rand()%255, rand()%255, rand()%255, 255); + canvas->push(move(shape)); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} - //Shape1 - auto shape1 = tvg::ShapeNode::gen(); +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} - /* Acquire shape1 pointer to access directly later. - instead, you should consider not to interrupt this pointer life-cycle. */ - auto pshape1 = shape1->get(); +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); - shape1->rect(0, 0, 400, 400, 0.1); - shape1->fill(255, 0, 0, 255); - shape1->rotate(0, 0, 45); //axis x, y, z + tvgtest(); - scene->push(move(shape1)); - canvas->push(move(scene)); + //Show the result using EFL... + elm_init(argc, argv); - //Draw first frame - canvas->draw(); - canvas->sync(); + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); - /* Clear the previous shape path and Prepare a new shape path. - You can call clear() to explicitly clear path data. */ - pshape1->rect(0, 0, 300, 300, 0.1); + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); - //Prepapre for drawing (this may work asynchronously) - pshape1->update(); + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); - //Draw second frame - canvas->draw(); - canvas->sync(); + Elm_Transit *transit = elm_transit_add(); + elm_transit_effect_add(transit, transit_cb, img, nullptr); + elm_transit_duration_set(transit, 2); + elm_transit_repeat_times_set(transit, -1); + elm_transit_auto_reverse_set(transit, EINA_TRUE); + elm_transit_go(transit); - //Explicitly clear all retained paint nodes. - canvas->clear(); + elm_run(); + elm_shutdown(); - //Terminate TizenVG Engine - tvg::Engine::term(); -} + //Terminate TizenVG Engine + tvg::Engine::term(); +} \ No newline at end of file -- 2.7.4 From a8864390e289d6ea156748c4c4017506f9687a43 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 11:14:14 +0900 Subject: [PATCH 10/16] canvas: code refactoring accept an extra argument in the clear() to clear paints node and clear buffer selectively. Change-Id: I83721e74358f546f325bb03fd1f36c7565174dd7 --- inc/tizenvg.h | 3 +-- src/lib/gl_engine/tvgGlRenderer.cpp | 5 +++++ src/lib/gl_engine/tvgGlRenderer.h | 1 + src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/tvgCanvas.cpp | 27 ++++++++++++++++----------- src/lib/tvgRenderCommon.h | 1 + src/lib/tvgSwCanvas.cpp | 12 ------------ 7 files changed, 25 insertions(+), 26 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index f325276..40f38ac 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -92,7 +92,7 @@ public: int reserve(size_t n) noexcept; virtual int push(std::unique_ptr paint) noexcept; - virtual int clear() noexcept; + virtual int clear(bool clearPaints = true) noexcept; virtual int update() noexcept; virtual int draw(bool async = true) noexcept; virtual int sync() = 0; @@ -179,7 +179,6 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - int clear() noexcept override; int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; int sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 38fb4de..8cf84da 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -35,6 +35,11 @@ struct GlShape /* External Class Implementation */ /************************************************************************/ +bool GlRenderer::clear() +{ + return true; +} + bool GlRenderer::render(const ShapeNode& shape, void *data) { GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 881d1ef..b6b9563 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -26,6 +26,7 @@ public: void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; bool dispose(const ShapeNode& shape, void *data) override; bool render(const ShapeNode& shape, void *data) override; + bool clear() override; size_t ref() override; size_t unref() override; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 5de6c12..95c5a0a 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -26,7 +26,7 @@ public: bool dispose(const ShapeNode& shape, void *data) override; bool render(const ShapeNode& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); - bool clear(); + bool clear() override; size_t ref() override; size_t unref() override; diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 3723083..e1f41b7 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -36,7 +36,7 @@ struct Canvas::Impl ~Impl() { - clear(); + clearPaints(); renderer->unref(); } @@ -55,23 +55,27 @@ struct Canvas::Impl return node->update(renderer); } - int clear() + bool clearRender() { assert(renderer); + return renderer->clear()); + } - auto ret = 0; + int clearPaints() + { + assert(renderer); for (auto node : nodes) { if (SceneNode *scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; } else if (ShapeNode *shape = dynamic_cast(node)) { - ret |= renderer->dispose(*shape, shape->engine()); + if (!renderer->dispose(*shape, shape->engine())) return -1; } delete(node); } nodes.clear(); - return ret; + return 0; } int update() @@ -91,16 +95,14 @@ struct Canvas::Impl { assert(renderer); - auto ret = 0; - for(auto node: nodes) { if (SceneNode *scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; } else if (ShapeNode *shape = dynamic_cast(node)) { - ret |= renderer->render(*shape, shape->engine()); + if (!renderer->render(*shape, shape->engine())) return -1; } } - return ret; + return 0; } }; @@ -137,11 +139,14 @@ int Canvas::push(unique_ptr paint) noexcept } -int Canvas::clear() noexcept +int Canvas::clear(bool clearPaints) noexcept { auto impl = pImpl.get(); assert(impl); - return impl->clear(); + auto ret = 0; + if (clearPaints) ret |= impl->clearPaints(); + ret |= impl->clearRender(); + return ret; } diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index ccbc415..07b33cd 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -36,6 +36,7 @@ public: virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; virtual bool dispose(const ShapeNode& shape, void *data) = 0; virtual bool render(const ShapeNode& shape, void *data) = 0; + virtual bool clear() = 0; virtual size_t ref() = 0; virtual size_t unref() = 0; }; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index cc26cbd..f75d79c 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -44,18 +44,6 @@ SwCanvas::~SwCanvas() { } - -int SwCanvas::clear() noexcept -{ - auto renderer = dynamic_cast(engine()); - assert(renderer); - - if (!renderer->clear()) return -1; - - return Canvas::clear(); -} - - int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(engine()); -- 2.7.4 From 0be7e0cf539dccc962153c7ba106d9858a2e72a0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 17:28:18 +0900 Subject: [PATCH 11/16] canvas: migrate render target clear call into draw(); Obivously, we need to clear target before drawing. Thus canvas request to renderers to clear buffer. the implementation is upto backend engines. Change-Id: Ib80da7f2260b021bcfed9fa13fb91c20218f9da0 --- inc/tizenvg.h | 2 +- src/lib/gl_engine/tvgGlRenderer.cpp | 2 ++ src/lib/tvgCanvas.cpp | 26 +++++++++----------------- src/lib/tvgSwCanvas.cpp | 1 - 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 40f38ac..8708695 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -92,7 +92,7 @@ public: int reserve(size_t n) noexcept; virtual int push(std::unique_ptr paint) noexcept; - virtual int clear(bool clearPaints = true) noexcept; + virtual int clear() noexcept; virtual int update() noexcept; virtual int draw(bool async = true) noexcept; virtual int sync() = 0; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 8cf84da..ca319ed 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -37,6 +37,8 @@ struct GlShape bool GlRenderer::clear() { + //TODO: (Request) to clear target + return true; } diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index e1f41b7..d9bf176 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -36,7 +36,7 @@ struct Canvas::Impl ~Impl() { - clearPaints(); + clear(); renderer->unref(); } @@ -55,13 +55,7 @@ struct Canvas::Impl return node->update(renderer); } - bool clearRender() - { - assert(renderer); - return renderer->clear()); - } - - int clearPaints() + int clear() { assert(renderer); @@ -82,19 +76,20 @@ struct Canvas::Impl { assert(renderer); - auto ret = 0; - for(auto node: nodes) { - ret |= node->update(renderer); + if (!node->update(renderer)) return -1; } - return ret; + return 0; } int draw() { assert(renderer); + //Clear render target before drawing + if (!renderer->clear()) return -1; + for(auto node: nodes) { if (SceneNode *scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; @@ -139,14 +134,11 @@ int Canvas::push(unique_ptr paint) noexcept } -int Canvas::clear(bool clearPaints) noexcept +int Canvas::clear() noexcept { auto impl = pImpl.get(); assert(impl); - auto ret = 0; - if (clearPaints) ret |= impl->clearPaints(); - ret |= impl->clearRender(); - return ret; + return impl->clear(); } diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index f75d79c..a4e49dd 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -50,7 +50,6 @@ int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexce assert(renderer); if (!renderer->target(buffer, stride, w, h)) return -1; - if (!renderer->clear()) return -1; return 0; } -- 2.7.4 From 60d104a40a96ae0ac6439e16c0b878a55e9571eb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 17:44:49 +0900 Subject: [PATCH 12/16] sw_engine: code refactoring. renamed internal variables for better readibility. Change-Id: I1ba7938401e8b7249c8bcc396be1ba3c109716cd --- src/lib/sw_engine/tvgSwCommon.h | 6 +++--- src/lib/sw_engine/tvgSwRle.cpp | 14 +++++++------- src/lib/sw_engine/tvgSwShape.cpp | 22 +++++++++++----------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4b31bcd..2900577 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -21,8 +21,8 @@ using namespace tvg; -constexpr auto SW_CURVE_TAG_ON = 1; -constexpr auto SW_CURVE_TAG_CUBIC = 2; +constexpr auto SW_CURVE_TYPE_POINT = 0; +constexpr auto SW_CURVE_TYPE_CUBIC = 1; constexpr auto SW_OUTLINE_FILL_WINDING = 0; constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1; @@ -62,7 +62,7 @@ struct SwOutline SwPoint* pts; //the outline's points size_t ptsCnt; //number of points in the glyph size_t reservedPtsCnt; - char* tags; //the points flags + uint8_t* types; //curve type uint8_t fillMode; //outline fill mode }; diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index f915a5d..ea2e451 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -606,27 +606,27 @@ static bool _decomposeOutline(RleWorker& rw) assert(limit); auto pt = outline->pts + first; - auto tags = outline->tags + first; + auto types = outline->types + first; /* A contour cannot start with a cubic control point! */ - if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline; + if (types[0] == SW_CURVE_TYPE_CUBIC) goto invalid_outline; _moveTo(rw, UPSCALE(outline->pts[first])); while (pt < limit) { assert(++pt); - assert(++tags); + assert(++types); //emit a single line_to - if (tags[0] == SW_CURVE_TAG_ON) { + if (types[0] == SW_CURVE_TYPE_POINT) { _lineTo(rw, UPSCALE(*pt)); - //tag cubic + //types cubic } else { - if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC) + if (pt + 1 > limit || types[1] != SW_CURVE_TYPE_CUBIC) goto invalid_outline; pt += 2; - tags += 2; + types += 2; if (pt <= limit) { _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0])); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 1f24a63..8223545 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -52,8 +52,8 @@ static void _growOutlinePoint(SwOutline& outline, size_t n) if (n == 0) { free(outline.pts); outline.pts = nullptr; - free(outline.tags); - outline.tags = nullptr; + free(outline.types); + outline.types = nullptr; outline.reservedPtsCnt = 0; outline.ptsCnt = 0; return; @@ -65,8 +65,8 @@ static void _growOutlinePoint(SwOutline& outline, size_t n) outline.reservedPtsCnt = n; outline.pts = static_cast(realloc(outline.pts, n * sizeof(SwPoint))); assert(outline.pts); - outline.tags = static_cast(realloc(outline.tags, n * sizeof(char))); - assert(outline.tags); + outline.types = static_cast(realloc(outline.types, n * sizeof(uint8_t))); + assert(outline.types); } @@ -87,7 +87,7 @@ static void _outlineMoveTo(SwOutline& outline, const Point* to) _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = TO_SWPOINT(to); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; if (outline.ptsCnt > 0) { _growOutlineContour(outline, 1); @@ -106,7 +106,7 @@ static void _outlineLineTo(SwOutline& outline, const Point* to) _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = TO_SWPOINT(to); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; } @@ -119,15 +119,15 @@ static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* _growOutlinePoint(outline, 3); outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC; ++outline.ptsCnt; outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl2); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC; ++outline.ptsCnt; outline.pts[outline.ptsCnt] = TO_SWPOINT(to); - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; } @@ -149,7 +149,7 @@ static bool _outlineClose(SwOutline& outline) _growOutlinePoint(outline, 1); outline.pts[outline.ptsCnt] = outline.pts[i]; - outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON; + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; return true; @@ -218,7 +218,7 @@ void _deleteOutline(SwShape& sdata) SwOutline* outline = sdata.outline; if (outline->cntrs) free(outline->cntrs); if (outline->pts) free(outline->pts); - if (outline->tags) free(outline->tags); + if (outline->types) free(outline->types); free(outline); sdata.outline = nullptr; -- 2.7.4 From 1b3661a0b0bceb790f6352a9c89d0f9d081ade16 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 18:06:06 +0900 Subject: [PATCH 13/16] common shape: renamed the method clear() to reset() Also, added one more showcase how to update only necessary properties of a shape while retaining other properties... Change-Id: If165bc7f8147cad0437e3ca2f7c007614c256248 --- .gitignore | 1 + inc/tizenvg.h | 2 +- src/lib/tvgShapeNode.cpp | 4 +- src/lib/tvgShapePath.h | 2 +- test/makefile | 1 + test/testDirectUpdate.cpp | 98 ++++++++++++++++++++++++++++++++++++++++ test/testUpdate.cpp | 112 +++++++++++++++++++++++----------------------- 7 files changed, 160 insertions(+), 60 deletions(-) create mode 100644 test/testDirectUpdate.cpp diff --git a/.gitignore b/.gitignore index 06f9099..a5643f4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ testPath testPathCopy testBlending testUpdate +testDirectUpdate diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 8708695..4a947da 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -117,7 +117,7 @@ public: ~ShapeNode(); int update(RenderMethod* engine) noexcept override; - int clear() noexcept; + int reset() noexcept; int moveTo(float x, float y) noexcept; int lineTo(float x, float y) noexcept; diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index b8397df..0a87211 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -103,12 +103,12 @@ int ShapeNode::update(RenderMethod* engine) noexcept } -int ShapeNode::clear() noexcept +int ShapeNode::reset() noexcept { auto impl = pImpl.get(); assert(impl); - impl->path->clear(); + impl->path->reset(); return 0; } diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 2849099..6b016f1 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -62,7 +62,7 @@ struct ShapePath reservePts(this->ptsCnt + ptsCnt); } - void clear() + void reset() { cmdCnt = 0; ptsCnt = 0; diff --git a/test/makefile b/test/makefile index e12fb31..23fd51a 100644 --- a/test/makefile +++ b/test/makefile @@ -7,3 +7,4 @@ all: gcc -o testPathCopy testPathCopy.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testBlending testBlending.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testUpdate testUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testDirectUpdate testDirectUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp new file mode 100644 index 0000000..ac6bdc3 --- /dev/null +++ b/test/testDirectUpdate.cpp @@ -0,0 +1,98 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; +unique_ptr canvas = nullptr; +tvg::ShapeNode* pShape = nullptr; + +void tvgtest() +{ + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape + auto shape = tvg::ShapeNode::gen(); + + /* Acquire shape pointer to access it again. + instead, you should consider not to interrupt this pointer life-cycle. */ + pShape = shape.get(); + + shape->appendRect(-100, -100, 200, 200, 0); + shape->fill(127, 255, 255, 255); + canvas->push(move(shape)); + + //Draw first frame + canvas->draw(); + canvas->sync(); +} + +void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + /* Update shape directly. + You can update only necessary properties of this shape, + while retaining other properties. */ + + pShape->reset(); //reset path + + pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + + //Update shape for drawing (this may work asynchronously) + pShape->update(canvas->engine()); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + Elm_Transit *transit = elm_transit_add(); + elm_transit_effect_add(transit, transit_cb, img, nullptr); + elm_transit_duration_set(transit, 2); + elm_transit_repeat_times_set(transit, -1); + elm_transit_auto_reverse_set(transit, EINA_TRUE); + elm_transit_go(transit); + + elm_run(); + elm_shutdown(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index c4250fb..97e81ec 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -11,80 +11,80 @@ unique_ptr canvas = nullptr; void tvgtest() { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - - //Shape - auto shape = tvg::ShapeNode::gen(); - shape->appendRect(-100, -100, 200, 200, 0); - shape->fill(255, 255, 255, 255); - canvas->push(move(shape)); - - //Draw first frame - canvas->draw(); - canvas->sync(); + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Shape + auto shape = tvg::ShapeNode::gen(); + shape->appendRect(-100, -100, 200, 200, 0); + shape->fill(255, 255, 255, 255); + canvas->push(move(shape)); + + //Draw first frame + canvas->draw(); + canvas->sync(); } void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) { - //Explicitly clear all retained paint nodes. - canvas->clear(); - - //Shape - auto shape = tvg::ShapeNode::gen(); - shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); - shape->fill(rand()%255, rand()%255, rand()%255, 255); - canvas->push(move(shape)); - - //Draw Next frames - canvas->draw(); - canvas->sync(); - - //Update Efl Canvas - Eo* img = (Eo*) effect; - evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + //Explicitly clear all retained paint nodes. + canvas->clear(); + + //Shape + auto shape = tvg::ShapeNode::gen(); + shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + shape->fill(rand()%255, rand()%255, rand()%255, 255); + canvas->push(move(shape)); + + //Draw Next frames + canvas->draw(); + canvas->sync(); + + //Update Efl Canvas + Eo* img = (Eo*) effect; + evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); } void win_del(void *data, Evas_Object *o, void *ev) { - elm_exit(); + elm_exit(); } int main(int argc, char **argv) { - //Initialize TizenVG Engine - tvg::Engine::init(); + //Initialize TizenVG Engine + tvg::Engine::init(); - tvgtest(); + tvgtest(); - //Show the result using EFL... - elm_init(argc, argv); + //Show the result using EFL... + elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); - Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); - elm_transit_duration_set(transit, 2); - elm_transit_repeat_times_set(transit, -1); - elm_transit_auto_reverse_set(transit, EINA_TRUE); - elm_transit_go(transit); + Elm_Transit *transit = elm_transit_add(); + elm_transit_effect_add(transit, transit_cb, img, nullptr); + elm_transit_duration_set(transit, 2); + elm_transit_repeat_times_set(transit, -1); + elm_transit_auto_reverse_set(transit, EINA_TRUE); + elm_transit_go(transit); - elm_run(); - elm_shutdown(); + elm_run(); + elm_shutdown(); - //Terminate TizenVG Engine - tvg::Engine::term(); -} \ No newline at end of file + //Terminate TizenVG Engine + tvg::Engine::term(); +} -- 2.7.4 From 42c56757df211b2f44f5fb25e1f35c980a0eb9aa Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 18:16:45 +0900 Subject: [PATCH 14/16] common: redesigned interfaces PaintNode -> Paint ShapeNode -> Shape SceneNode -> Scene We can keep clean and neat shorter names. Change-Id: Ic8521d456d947985e5fbe1ba2bde06faa1f52469 --- inc/tizenvg.h | 30 ++++++++++---------- src/lib/gl_engine/tvgGlRenderer.cpp | 6 ++-- src/lib/gl_engine/tvgGlRenderer.h | 6 ++-- src/lib/meson.build | 4 +-- src/lib/sw_engine/tvgSwCommon.h | 8 +++--- src/lib/sw_engine/tvgSwRenderer.cpp | 6 ++-- src/lib/sw_engine/tvgSwRenderer.h | 6 ++-- src/lib/sw_engine/tvgSwShape.cpp | 6 ++-- src/lib/tvgCanvas.cpp | 18 ++++++------ src/lib/tvgRenderCommon.h | 6 ++-- src/lib/{tvgSceneNode.cpp => tvgScene.cpp} | 22 +++++++-------- src/lib/{tvgShapeNode.cpp => tvgShape.cpp} | 44 +++++++++++++++--------------- test/testBlending.cpp | 10 +++---- test/testBoundary.cpp | 10 +++---- test/testComposition.cpp | 2 +- test/testDirectUpdate.cpp | 4 +-- test/testGradient.cpp | 4 +-- test/testMergeShapes.cpp | 2 +- test/testMultiShapes.cpp | 6 ++-- test/testPath.cpp | 4 +-- test/testPathCopy.cpp | 4 +-- test/testScene.cpp | 8 +++--- test/testShape.cpp | 2 +- test/testStroke.cpp | 2 +- test/testUpdate.cpp | 4 +-- 25 files changed, 112 insertions(+), 112 deletions(-) rename src/lib/{tvgSceneNode.cpp => tvgScene.cpp} (72%) rename src/lib/{tvgShapeNode.cpp => tvgShape.cpp} (82%) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 4a947da..b443d50 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -61,17 +61,17 @@ struct Point /** - * @class PaintNode + * @class Paint * * @ingroup TizenVG * * @brief description... * */ -class TIZENVG_EXPORT PaintNode +class TIZENVG_EXPORT Paint { public: - virtual ~PaintNode() {} + virtual ~Paint() {} virtual int update(RenderMethod*) = 0; }; @@ -91,7 +91,7 @@ public: virtual ~Canvas(); int reserve(size_t n) noexcept; - virtual int push(std::unique_ptr paint) noexcept; + virtual int push(std::unique_ptr paint) noexcept; virtual int clear() noexcept; virtual int update() noexcept; virtual int draw(bool async = true) noexcept; @@ -104,17 +104,17 @@ public: /** - * @class ShapeNode + * @class Shape * * @ingroup TizenVG * * @brief description... * */ -class TIZENVG_EXPORT ShapeNode final : public PaintNode +class TIZENVG_EXPORT Shape final : public Paint { public: - ~ShapeNode(); + ~Shape(); int update(RenderMethod* engine) noexcept override; int reset() noexcept; @@ -134,35 +134,35 @@ public: int pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; - static std::unique_ptr gen() noexcept; + static std::unique_ptr gen() noexcept; //FIXME: Ugly... Better design? void *engine() noexcept; - _TIZENVG_DECLARE_PRIVATE(ShapeNode); + _TIZENVG_DECLARE_PRIVATE(Shape); }; /** - * @class SceneNode + * @class Scene * * @ingroup TizenVG * * @brief description... * */ -class TIZENVG_EXPORT SceneNode final : public PaintNode +class TIZENVG_EXPORT Scene final : public Paint { public: - ~SceneNode(); + ~Scene(); int update(RenderMethod* engine) noexcept override; - int push(std::unique_ptr shape) noexcept; + int push(std::unique_ptr shape) noexcept; - static std::unique_ptr gen() noexcept; + static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(SceneNode); + _TIZENVG_DECLARE_PRIVATE(Scene); }; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index ca319ed..4e0aa51 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -42,7 +42,7 @@ bool GlRenderer::clear() return true; } -bool GlRenderer::render(const ShapeNode& shape, void *data) +bool GlRenderer::render(const Shape& shape, void *data) { GlShape* sdata = static_cast(data); if (!sdata) return false; @@ -53,7 +53,7 @@ bool GlRenderer::render(const ShapeNode& shape, void *data) } -bool GlRenderer::dispose(const ShapeNode& shape, void *data) +bool GlRenderer::dispose(const Shape& shape, void *data) { GlShape* sdata = static_cast(data); if (!sdata) return false; @@ -65,7 +65,7 @@ bool GlRenderer::dispose(const ShapeNode& shape, void *data) } -void* GlRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index b6b9563..a508eed 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -23,9 +23,9 @@ namespace tvg class GlRenderer : public RenderMethod { public: - void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; - bool dispose(const ShapeNode& shape, void *data) override; - bool render(const ShapeNode& shape, void *data) override; + void* prepare(const Shape& shape, void* data, UpdateFlag flags) override; + bool dispose(const Shape& shape, void *data) override; + bool render(const Shape& shape, void *data) override; bool clear() override; size_t ref() override; size_t unref() override; diff --git a/src/lib/meson.build b/src/lib/meson.build index 976aa5e..5b47bcf 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -9,8 +9,8 @@ source_file = [ 'tvgCanvas.cpp', 'tvgSwCanvas.cpp', 'tvgGlCanvas.cpp', - 'tvgSceneNode.cpp', - 'tvgShapeNode.cpp' + 'tvgScene.cpp', + 'tvgShape.cpp' ] src_dep = declare_dependency( diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 2900577..4d654c9 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -93,10 +93,10 @@ struct SwShape }; void shapeReset(SwShape& sdata); -bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata); -void shapeDelOutline(const ShapeNode& shape, SwShape& sdata); -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip); -bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); +bool shapeGenOutline(const Shape& shape, SwShape& sdata); +void shapeDelOutline(const Shape& shape, SwShape& sdata); +bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); +bool shapeTransformOutline(const Shape& shape, SwShape& sdata); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 983a1ca..eda12cc 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -58,7 +58,7 @@ bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) } -bool SwRenderer::render(const ShapeNode& shape, void *data) +bool SwRenderer::render(const Shape& shape, void *data) { SwShape* sdata = static_cast(data); if (!sdata) return false; @@ -72,7 +72,7 @@ bool SwRenderer::render(const ShapeNode& shape, void *data) } -bool SwRenderer::dispose(const ShapeNode& shape, void *data) +bool SwRenderer::dispose(const Shape& shape, void *data) { SwShape* sdata = static_cast(data); if (!sdata) return false; @@ -81,7 +81,7 @@ bool SwRenderer::dispose(const ShapeNode& shape, void *data) return true; } -void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 95c5a0a..ce87fa9 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,9 +22,9 @@ class SwRenderer : public RenderMethod public: Surface surface; - void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override; - bool dispose(const ShapeNode& shape, void *data) override; - bool render(const ShapeNode& shape, void *data) override; + void* prepare(const Shape& shape, void* data, UpdateFlag flags) override; + bool dispose(const Shape& shape, void *data) override; + bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); bool clear() override; size_t ref() override; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 8223545..5a1c6c3 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -228,14 +228,14 @@ void _deleteOutline(SwShape& sdata) /* External Class Implementation */ /************************************************************************/ -bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) +bool shapeTransformOutline(const Shape& shape, SwShape& sdata) { //TODO: return true; } -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip) +bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) { if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) goto end; if (!_updateBBox(sdata)) goto end; @@ -262,7 +262,7 @@ void shapeReset(SwShape& sdata) } -bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata) +bool shapeGenOutline(const Shape& shape, SwShape& sdata) { const PathCommand* cmds = nullptr; auto cmdCnt = shape.pathCommands(&cmds); diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index d9bf176..84a1327 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -26,10 +26,10 @@ struct Canvas::Impl { - vector nodes; + vector nodes; RenderMethod* renderer; - Impl(RenderMethod *pRenderer):renderer(pRenderer) + Impl(RenderMethod* pRenderer):renderer(pRenderer) { renderer->ref(); } @@ -47,9 +47,9 @@ struct Canvas::Impl return 0; } - int push(unique_ptr paint) + int push(unique_ptr paint) { - PaintNode *node = paint.release(); + Paint* node = paint.release(); assert(node); nodes.push_back(node); return node->update(renderer); @@ -60,9 +60,9 @@ struct Canvas::Impl assert(renderer); for (auto node : nodes) { - if (SceneNode *scene = dynamic_cast(node)) { + if (Scene* scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; - } else if (ShapeNode *shape = dynamic_cast(node)) { + } else if (Shape *shape = dynamic_cast(node)) { if (!renderer->dispose(*shape, shape->engine())) return -1; } delete(node); @@ -91,9 +91,9 @@ struct Canvas::Impl if (!renderer->clear()) return -1; for(auto node: nodes) { - if (SceneNode *scene = dynamic_cast(node)) { + if (Scene* scene = dynamic_cast(node)) { cout << "TODO: " << scene << endl; - } else if (ShapeNode *shape = dynamic_cast(node)) { + } else if (Shape *shape = dynamic_cast(node)) { if (!renderer->render(*shape, shape->engine())) return -1; } } @@ -125,7 +125,7 @@ int Canvas::reserve(size_t n) noexcept } -int Canvas::push(unique_ptr paint) noexcept +int Canvas::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 07b33cd..5d61991 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -33,9 +33,9 @@ class RenderMethod public: enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; virtual ~RenderMethod() {} - virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0; - virtual bool dispose(const ShapeNode& shape, void *data) = 0; - virtual bool render(const ShapeNode& shape, void *data) = 0; + virtual void* prepare(const Shape& shape, void* data, UpdateFlag flags) = 0; + virtual bool dispose(const Shape& shape, void *data) = 0; + virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; virtual size_t ref() = 0; virtual size_t unref() = 0; diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgScene.cpp similarity index 72% rename from src/lib/tvgSceneNode.cpp rename to src/lib/tvgScene.cpp index db3ae1d..7572561 100644 --- a/src/lib/tvgSceneNode.cpp +++ b/src/lib/tvgScene.cpp @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_SCENE_NODE_CPP_ -#define _TVG_SCENE_NODE_CPP_ +#ifndef _TVG_SCENE_CPP_ +#define _TVG_SCENE_CPP_ #include "tvgCommon.h" @@ -23,7 +23,7 @@ /* Internal Class Implementation */ /************************************************************************/ -struct SceneNode::Impl +struct Scene::Impl { }; @@ -34,34 +34,34 @@ struct SceneNode::Impl /* External Class Implementation */ /************************************************************************/ -SceneNode::SceneNode() : pImpl(make_unique()) +Scene::Scene() : pImpl(make_unique()) { } -SceneNode::~SceneNode() +Scene::~Scene() { - cout << "SceneNode(" << this << ") destroyed!" << endl; + cout << "Scene(" << this << ") destroyed!" << endl; } -unique_ptr SceneNode::gen() noexcept +unique_ptr Scene::gen() noexcept { - return unique_ptr(new SceneNode); + return unique_ptr(new Scene); } -int SceneNode::push(unique_ptr shape) noexcept +int Scene::push(unique_ptr shape) noexcept { return 0; } -int SceneNode::update(RenderMethod* engine) noexcept +int Scene::update(RenderMethod* engine) noexcept { return 0; } -#endif /* _TVG_SCENE_NODE_CPP_ */ +#endif /* _TVG_SCENE_CPP_ */ diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShape.cpp similarity index 82% rename from src/lib/tvgShapeNode.cpp rename to src/lib/tvgShape.cpp index 0a87211..5fbfce8 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShape.cpp @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TVG_SHAPE_NODE_CPP_ -#define _TVG_SHAPE_NODE_CPP_ +#ifndef _TVG_SHAPE_CPP_ +#define _TVG_SHAPE_CPP_ #include "tvgCommon.h" #include "tvgShapePath.h" @@ -41,7 +41,7 @@ struct ShapeTransform }; -struct ShapeNode::Impl +struct Shape::Impl { ShapeTransform *transform = nullptr; ShapeFill *fill = nullptr; @@ -68,23 +68,23 @@ struct ShapeNode::Impl /* External Class Implementation */ /************************************************************************/ -ShapeNode :: ShapeNode() : pImpl(make_unique()) +Shape :: Shape() : pImpl(make_unique()) { } -ShapeNode :: ~ShapeNode() +Shape :: ~Shape() { } -unique_ptr ShapeNode::gen() noexcept +unique_ptr Shape::gen() noexcept { - return unique_ptr(new ShapeNode); + return unique_ptr(new Shape); } -void* ShapeNode::engine() noexcept +void* Shape::engine() noexcept { auto impl = pImpl.get(); assert(impl); @@ -92,7 +92,7 @@ void* ShapeNode::engine() noexcept } -int ShapeNode::update(RenderMethod* engine) noexcept +int Shape::update(RenderMethod* engine) noexcept { auto impl = pImpl.get(); assert(impl); @@ -103,7 +103,7 @@ int ShapeNode::update(RenderMethod* engine) noexcept } -int ShapeNode::reset() noexcept +int Shape::reset() noexcept { auto impl = pImpl.get(); assert(impl); @@ -114,7 +114,7 @@ int ShapeNode::reset() noexcept } -int ShapeNode::pathCommands(const PathCommand** cmds) const noexcept +int Shape::pathCommands(const PathCommand** cmds) const noexcept { auto impl = pImpl.get(); assert(impl && cmds); @@ -125,7 +125,7 @@ int ShapeNode::pathCommands(const PathCommand** cmds) const noexcept } -int ShapeNode::pathCoords(const Point** pts) const noexcept +int Shape::pathCoords(const Point** pts) const noexcept { auto impl = pImpl.get(); assert(impl && pts); @@ -136,7 +136,7 @@ int ShapeNode::pathCoords(const Point** pts) const noexcept } -int ShapeNode::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept +int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept { if (cmdCnt < 0 || ptsCnt < 0) return -1; assert(cmds && pts); @@ -151,7 +151,7 @@ int ShapeNode::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* p } -int ShapeNode::moveTo(float x, float y) noexcept +int Shape::moveTo(float x, float y) noexcept { auto impl = pImpl.get(); assert(impl); @@ -162,7 +162,7 @@ int ShapeNode::moveTo(float x, float y) noexcept } -int ShapeNode::lineTo(float x, float y) noexcept +int Shape::lineTo(float x, float y) noexcept { auto impl = pImpl.get(); assert(impl); @@ -173,7 +173,7 @@ int ShapeNode::lineTo(float x, float y) noexcept } -int ShapeNode::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept +int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { auto impl = pImpl.get(); assert(impl); @@ -184,7 +184,7 @@ int ShapeNode::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, floa } -int ShapeNode::close() noexcept +int Shape::close() noexcept { auto impl = pImpl.get(); assert(impl); @@ -195,7 +195,7 @@ int ShapeNode::close() noexcept } -int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept +int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); assert(impl); @@ -215,7 +215,7 @@ int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) no } -int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept +int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept { auto impl = pImpl.get(); assert(impl); @@ -254,7 +254,7 @@ int ShapeNode::appendRect(float x, float y, float w, float h, float cornerRadius } -int ShapeNode::fill(size_t r, size_t g, size_t b, size_t a) noexcept +int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept { auto impl = pImpl.get(); assert(impl); @@ -268,7 +268,7 @@ int ShapeNode::fill(size_t r, size_t g, size_t b, size_t a) noexcept } -int ShapeNode::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept { auto impl = pImpl.get(); assert(impl); @@ -281,4 +281,4 @@ int ShapeNode::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept return 0; } -#endif //_TVG_SHAPE_NODE_CPP_ +#endif //_TVG_SHAPE_CPP_ diff --git a/test/testBlending.cpp b/test/testBlending.cpp index ef142aa..58ae025 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -19,25 +19,25 @@ void tvgtest() canvas->reserve(5); //Prepare Round Rectangle - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); //r, g, b, a canvas->push(move(shape1)); //Prepare Circle - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH shape2->fill(170, 170, 0, 170); //r, g, b, a canvas->push(move(shape2)); //Prepare Ellipse - auto shape3 = tvg::ShapeNode::gen(); + auto shape3 = tvg::Shape::gen(); shape3->appendCircle(400, 400, 250, 100); //cx, cy, radiusW, radiusH shape3->fill(100, 100, 100, 100); //r, g, b, a canvas->push(move(shape3)); //Prepare Star - auto shape4 = tvg::ShapeNode::gen(); + auto shape4 = tvg::Shape::gen(); shape4->moveTo(199, 234); shape4->lineTo(253, 343); shape4->lineTo(374, 360); @@ -53,7 +53,7 @@ void tvgtest() canvas->push(move(shape4)); //Prepare Opaque Ellipse - auto shape5 = tvg::ShapeNode::gen(); + auto shape5 = tvg::Shape::gen(); shape5->appendCircle(600, 650, 200, 150); shape5->fill(0, 0, 255, 255); canvas->push(move(shape5)); diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 7d305be..c5d39f6 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -19,31 +19,31 @@ void tvgtest() canvas->reserve(5); //reserve 5 shape nodes (optional) //Prepare Shape1 - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendRect(-100, -100, 1000, 1000, 50); shape1->fill(255, 255, 255, 255); canvas->push(move(shape1)); //Prepare Shape2 - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->appendRect(-100, -100, 250, 250, 50); shape2->fill(0, 0, 255, 255); canvas->push(move(shape2)); //Prepare Shape3 - auto shape3 = tvg::ShapeNode::gen(); + auto shape3 = tvg::Shape::gen(); shape3->appendRect(500, 500, 550, 550, 0); shape3->fill(0, 255, 255, 255); canvas->push(move(shape3)); //Prepare Shape4 - auto shape4 = tvg::ShapeNode::gen(); + auto shape4 = tvg::Shape::gen(); shape4->appendCircle(800, 100, 200, 200); shape4->fill(255, 255, 0, 255); canvas->push(move(shape4)); //Prepare Shape5 - auto shape5 = tvg::ShapeNode::gen(); + auto shape5 = tvg::Shape::gen(); shape5->appendCircle(200, 650, 250, 200); shape5->fill(0, 0, 0, 255); canvas->push(move(shape5)); diff --git a/test/testComposition.cpp b/test/testComposition.cpp index cf5ed26..57a8e43 100644 --- a/test/testComposition.cpp +++ b/test/testComposition.cpp @@ -22,7 +22,7 @@ int main(int argc, char **argv) auto canvas2 = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Create a Shape - auto shape = tvg::ShapeNode::gen(); + auto shape = tvg::Shape::gen(); shape->composite(canvas, tvg::CompMaskAdd); //Draw the Scene onto the Canvas diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index ac6bdc3..df5384d 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -8,7 +8,7 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; unique_ptr canvas = nullptr; -tvg::ShapeNode* pShape = nullptr; +tvg::Shape* pShape = nullptr; void tvgtest() { @@ -17,7 +17,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Shape - auto shape = tvg::ShapeNode::gen(); + auto shape = tvg::Shape::gen(); /* Acquire shape pointer to access it again. instead, you should consider not to interrupt this pointer life-cycle. */ diff --git a/test/testGradient.cpp b/test/testGradient.cpp index a696839..6a7b6ba 100644 --- a/test/testGradient.cpp +++ b/test/testGradient.cpp @@ -16,7 +16,7 @@ int main(int argc, char **argv) auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Prepare a Shape - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius //Linear Gradient Fill @@ -30,7 +30,7 @@ int main(int argc, char **argv) canvas->push(move(shape1)); //Prepare Circle - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->circle(400, 400, 200); //cx, cy, radius //Radial Gradient Fill diff --git a/test/testMergeShapes.cpp b/test/testMergeShapes.cpp index 27ef0c5..8cff17d 100644 --- a/test/testMergeShapes.cpp +++ b/test/testMergeShapes.cpp @@ -18,7 +18,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius shape1->appendRect(100, 100, 300, 300, 100); //x, y, w, h, cornerRadius shape1->appendCircle(400, 400, 100, 100); //cx, cy, radiusW, radiusH diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index d53e9fc..2539382 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -19,19 +19,19 @@ void tvgtest() canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); //r, g, b, a canvas->push(move(shape1)); //Prepare Circle - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH shape2->fill(255, 255, 0, 255); //r, g, b, a canvas->push(move(shape2)); //Prepare Ellipse - auto shape3 = tvg::ShapeNode::gen(); + auto shape3 = tvg::Shape::gen(); shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH shape3->fill(0, 255, 255, 255); //r, g, b, a canvas->push(move(shape3)); diff --git a/test/testPath.cpp b/test/testPath.cpp index 1ae897d..c2ca875 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -18,7 +18,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Star - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); //Appends Paths shape1->moveTo(199, 34); @@ -36,7 +36,7 @@ void tvgtest() canvas->push(move(shape1)); //Circle - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); auto cx = 550.0f; auto cy = 550.0f; diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index e555226..28d19eb 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -46,7 +46,7 @@ void tvgtest() pts[8] = {26, 161}; //LineTo pts[9] = {146, 143}; //LineTo - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendPath(cmds, 11, pts, 10); //copy path data shape1->fill(0, 255, 0, 255); canvas->push(move(shape1)); @@ -87,7 +87,7 @@ void tvgtest() pts2[11] = {cx - halfRadius, cy - radius}; //Ctrl2 pts2[12] = {cx, cy - radius}; //To - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->appendPath(cmds2, 6, pts2, 13); //copy path data shape2->fill(255, 255, 0, 255); canvas->push(move(shape2)); diff --git a/test/testScene.cpp b/test/testScene.cpp index f3010dc..3232b65 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -16,25 +16,25 @@ int main(int argc, char **argv) auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Create a Scene - auto scene = tvg::SceneNode::gen(); + auto scene = tvg::Scene::gen(); scene->reserve(3); //reserve 3 shape nodes (optional) //Shape1 - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->rect(0, 0, 400, 400, 0.1); shape1->fill(255, 0, 0, 255); shape1->rotate(0, 0, 45); //axis x, y, z scene->push(move(shape1)); //Shape2 - auto shape2 = tvg::ShapeNode::gen(); + auto shape2 = tvg::Shape::gen(); shape2->rect(0, 0, 400, 400, 0.1); shape2->fill(0, 255, 0, 255); shape2->transform(matrix); //by matrix (var matrix[4 * 4];) scene->push(move(shape2)); //Shape3 - auto shape3 = tvg::ShapeNode::gen(); + auto shape3 = tvg::Shape::gen(); shape3->rect(0, 0, 400, 400, 0.1); shape3->fill(0, 0, 255, 255); shape3->origin(100, 100); //offset diff --git a/test/testShape.cpp b/test/testShape.cpp index 4386637..8f60263 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -18,7 +18,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Prepare a Shape (Rectangle) - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->appendRect(100, 100, 400, 400, 0); //x, y, w, h, cornerRadius shape1->fill(255, 0, 0, 255); //r, g, b, a diff --git a/test/testStroke.cpp b/test/testStroke.cpp index de84c32..e2ae1bc 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -16,7 +16,7 @@ int main(int argc, char **argv) auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); //Prepare a Shape - auto shape1 = tvg::ShapeNode::gen(); + auto shape1 = tvg::Shape::gen(); shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 97e81ec..f225624 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -16,7 +16,7 @@ void tvgtest() canvas->target(buffer, WIDTH, WIDTH, HEIGHT); //Shape - auto shape = tvg::ShapeNode::gen(); + auto shape = tvg::Shape::gen(); shape->appendRect(-100, -100, 200, 200, 0); shape->fill(255, 255, 255, 255); canvas->push(move(shape)); @@ -32,7 +32,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres canvas->clear(); //Shape - auto shape = tvg::ShapeNode::gen(); + auto shape = tvg::Shape::gen(); shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); shape->fill(rand()%255, rand()%255, rand()%255, 255); canvas->push(move(shape)); -- 2.7.4 From 30ac2da1a39578401eaf6dac3183f681b5385b1f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 2 May 2020 22:30:48 +0900 Subject: [PATCH 15/16] common shape: support scale/rotate transform rotate(), scale() won't be retained. When you call reset() for the shape, these values will be reset as well. These are working in fire & forget method, it actually modify the path data for avoiding compuatation every frames. Thus user needs to keep the last values to understand the final accumulated values. Change-Id: I41f260271cdefc977eea01a778d49632440c777f --- inc/tizenvg.h | 16 +++++++++- src/lib/tvgScene.cpp | 20 ++++++++++++- src/lib/tvgShape.cpp | 76 ++++++++++++++++++++++++++++++++++++----------- src/lib/tvgShapePath.h | 65 ++++++++++++++++++++++++++++++++++++++++ test/testDirectUpdate.cpp | 7 +++++ test/testUpdate.cpp | 3 ++ 6 files changed, 167 insertions(+), 20 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index b443d50..8325440 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -72,7 +72,13 @@ class TIZENVG_EXPORT Paint { public: virtual ~Paint() {} + virtual int update(RenderMethod*) = 0; + + virtual int rotate(float degree) = 0; + virtual int scale(float factor) = 0; + + virtual int bounds(float&x, float& y, float& w, float& h) const = 0; }; @@ -130,9 +136,13 @@ public: int fill(size_t r, size_t g, size_t b, size_t a) noexcept; + int rotate(float degree) noexcept override; + int scale(float factor) noexcept override; + int pathCommands(const PathCommand** cmds) const noexcept; int pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + int bounds(float&x, float& y, float& w, float& h) const noexcept override; static std::unique_ptr gen() noexcept; @@ -157,9 +167,13 @@ public: ~Scene(); int update(RenderMethod* engine) noexcept override; - int push(std::unique_ptr shape) noexcept; + int rotate(float degree) noexcept override; + int scale(float factor) noexcept override; + + int bounds(float&x, float& y, float& w, float& h) const noexcept override; + static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(Scene); diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 7572561..bf937a2 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -64,4 +64,22 @@ int Scene::update(RenderMethod* engine) noexcept return 0; } -#endif /* _TVG_SCENE_CPP_ */ + +int Scene::scale(float scaleFacator) noexcept +{ + return 0; +} + + +int Scene::rotate(float degree) noexcept +{ + return 0; +} + + +int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept +{ + return 0; +} + +#endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 5fbfce8..9c41c08 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -35,19 +35,14 @@ struct ShapeStroke }; -struct ShapeTransform -{ - float e[4*4]; -}; - - struct Shape::Impl { - ShapeTransform *transform = nullptr; ShapeFill *fill = nullptr; ShapeStroke *stroke = nullptr; ShapePath *path = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a + float scale = 1; + float rotate = 0; void *edata = nullptr; //engine data Impl() : path(new ShapePath) @@ -59,7 +54,14 @@ struct Shape::Impl if (path) delete(path); if (stroke) delete(stroke); if (fill) delete(fill); - if (transform) delete(transform); + } + + bool update() + { + if (path->scale(scale)) scale = 1; + if (path->rotate(rotate)) rotate = 0; + + return true; } }; @@ -97,6 +99,7 @@ int Shape::update(RenderMethod* engine) noexcept auto impl = pImpl.get(); assert(impl); + if (!impl->update()) return -1; impl->edata = engine->prepare(*this, impl->edata, RenderMethod::UpdateFlag::All); if (impl->edata) return 0; return - 1; @@ -106,7 +109,7 @@ int Shape::update(RenderMethod* engine) noexcept int Shape::reset() noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->reset(); @@ -117,7 +120,7 @@ int Shape::reset() noexcept int Shape::pathCommands(const PathCommand** cmds) const noexcept { auto impl = pImpl.get(); - assert(impl && cmds); + assert(impl && impl->path && cmds); *cmds = impl->path->cmds; @@ -128,7 +131,7 @@ int Shape::pathCommands(const PathCommand** cmds) const noexcept int Shape::pathCoords(const Point** pts) const noexcept { auto impl = pImpl.get(); - assert(impl && pts); + assert(impl && impl->path && pts); *pts = impl->path->pts; @@ -142,7 +145,7 @@ int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, assert(cmds && pts); auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->grow(cmdCnt, ptsCnt); impl->path->append(cmds, cmdCnt, pts, ptsCnt); @@ -154,7 +157,7 @@ int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, int Shape::moveTo(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->moveTo(x, y); @@ -165,7 +168,7 @@ int Shape::moveTo(float x, float y) noexcept int Shape::lineTo(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->lineTo(x, y); @@ -176,7 +179,7 @@ int Shape::lineTo(float x, float y) noexcept int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); @@ -187,7 +190,7 @@ int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) int Shape::close() noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); impl->path->close(); @@ -198,7 +201,7 @@ int Shape::close() noexcept int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); auto halfKappaW = radiusW * PATH_KAPPA; auto halfKappaH = radiusH * PATH_KAPPA; @@ -218,7 +221,7 @@ int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexce int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept { auto impl = pImpl.get(); - assert(impl); + assert(impl && impl->path); //clamping cornerRadius by minimum size auto min = (w < h ? w : h) * 0.5f; @@ -281,4 +284,41 @@ int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept return 0; } + +int Shape::scale(float factor) noexcept +{ + if (factor < FLT_EPSILON || fabsf(factor - 1) <= FLT_EPSILON) return -1; + + auto impl = pImpl.get(); + assert(impl); + + impl->scale *= factor; + + return 0; +} + + +int Shape::rotate(float degree) noexcept +{ + if (fabsf(degree) <= FLT_EPSILON) return -1; + + auto impl = pImpl.get(); + assert(impl); + + impl->rotate += degree; + + return 0; +} + + +int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept +{ + auto impl = pImpl.get(); + assert(impl && impl->path); + + if (!impl->path->bounds(x, y, w, h)) return -1; + + return 0; +} + #endif //_TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 6b016f1..9c42829 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -112,6 +112,71 @@ struct ShapePath if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); cmds[cmdCnt++] = PathCommand::Close; } + + bool bounds(float& x, float& y, float& w, float& h) + { + if (ptsCnt == 0) return false; + + Point min = { pts[0].x, pts[0].y }; + Point max = { pts[0].x, pts[0].y }; + + for(size_t i = 1; i < ptsCnt; ++i) { + if (pts[i].x < min.x) min.x = pts[i].x; + if (pts[i].y < min.y) min.y = pts[i].y; + if (pts[i].x > max.x) max.x = pts[i].x; + if (pts[i].y > max.y) max.y = pts[i].y; + } + + x = min.x; + y = min.y; + w = max.x - min.x; + h = max.y - min.y; + + return true; + } + + bool rotate(float degree) + { + constexpr auto PI = 3.141592f; + + if (fabsf(degree) <= FLT_EPSILON) return false; + + float x, y, w, h; + if (!bounds(x, y, w, h)) return false; + + auto radian = degree / 180.0f * PI; + auto cx = x + w * 0.5f; + auto cy = y + h * 0.5f; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + for(size_t i = 0; i < ptsCnt; ++i) { + auto dx = pts[i].x - cx; + auto dy = pts[i].y - cy; + pts[i].x = (cosVal * dx - sinVal * dy) + cx; + pts[i].y = (sinVal * dx + cosVal * dy) + cy; + } + + return true; + } + + bool scale(float factor) + { + if (fabsf(factor - 1) <= FLT_EPSILON) return false; + + float x, y, w, h; + if (!bounds(x, y, w, h)) return false; + + auto cx = x + w * 0.5f; + auto cy = y + h * 0.5f; + + for(size_t i = 0; i < ptsCnt; ++i) { + pts[i].x = (pts[i].x - cx) * factor + cx; + pts[i].y = (pts[i].y - cy) * factor + cy; + } + + return true; + } }; #endif //_TVG_SHAPE_PATH_CPP_ diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index df5384d..1888de4 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -25,6 +25,7 @@ void tvgtest() shape->appendRect(-100, -100, 200, 200, 0); shape->fill(127, 255, 255, 255); + shape->rotate(45); canvas->push(move(shape)); //Draw first frame @@ -42,6 +43,12 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + /* rotate, scale won't be retained, when you call reset() for the shape, these values will be reset as well. + These are working in fire & forget method, it actually modify the path data for avoiding compuatation every frames. + Thus user needs to keep the last values to understand the final accumulated values. */ + pShape->rotate(45); + pShape->scale(1 - 0.75 * progress); + //Update shape for drawing (this may work asynchronously) pShape->update(canvas->engine()); diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index f225624..d941e26 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -35,6 +35,9 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres auto shape = tvg::Shape::gen(); shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); shape->fill(rand()%255, rand()%255, rand()%255, 255); + shape->scale(1 - 0.75 * progress); + shape->rotate(360 * progress); + canvas->push(move(shape)); //Draw Next frames -- 2.7.4 From 682bc252987ac42059c089f3a6ec0b3da26f86a0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 3 May 2020 02:02:43 +0900 Subject: [PATCH 16/16] common shape: revise scale/rotate approach. Come to think of it, this optimized method is not so useful, it could just bring the user misunderstanding and not to efficient as I expected in the most cases. So, changed policy for transformation behaviors. it keeps the properties as others but leaves it to the backend implementation. Plus, this change contains the correct RenderUpdateFlag. You can refer the flag in the backend to figure out which kinds of properites has been updated Change-Id: Ibe0494712598a8161950b9ae2e22ac45bed1c47b --- inc/tizenvg.h | 10 ++++- src/lib/gl_engine/tvgGlRenderer.cpp | 2 +- src/lib/gl_engine/tvgGlRenderer.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRenderer.cpp | 7 ++-- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 79 ++++++++++++++++++++++++++++--------- src/lib/tvgRenderCommon.h | 5 ++- src/lib/tvgScene.cpp | 12 ++++++ src/lib/tvgShape.cpp | 68 ++++++++++++++++++++++--------- src/lib/tvgShapePath.h | 43 -------------------- test/testDirectUpdate.cpp | 7 +--- 12 files changed, 143 insertions(+), 96 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 8325440..93e13fc 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -79,6 +79,8 @@ public: virtual int scale(float factor) = 0; virtual int bounds(float&x, float& y, float& w, float& h) const = 0; + virtual float scale() const = 0; + virtual float rotate() const = 0; }; @@ -139,10 +141,12 @@ public: int rotate(float degree) noexcept override; int scale(float factor) noexcept override; - int pathCommands(const PathCommand** cmds) const noexcept; - int pathCoords(const Point** pts) const noexcept; + size_t pathCommands(const PathCommand** cmds) const noexcept; + size_t pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; int bounds(float&x, float& y, float& w, float& h) const noexcept override; + float scale() const noexcept override; + float rotate() const noexcept override; static std::unique_ptr gen() noexcept; @@ -173,6 +177,8 @@ public: int scale(float factor) noexcept override; int bounds(float&x, float& y, float& w, float& h) const noexcept override; + float scale() const noexcept override; + float rotate() const noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 4e0aa51..0b1a9c7 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) } -void* GlRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index a508eed..e9e5abe 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -23,7 +23,7 @@ namespace tvg class GlRenderer : public RenderMethod { public: - void* prepare(const Shape& shape, void* data, UpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool clear() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4d654c9..00ff315 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -94,7 +94,7 @@ struct SwShape void shapeReset(SwShape& sdata); bool shapeGenOutline(const Shape& shape, SwShape& sdata); -void shapeDelOutline(const Shape& shape, SwShape& sdata); +void shapeDelOutline(SwShape& sdata); bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); bool shapeTransformOutline(const Shape& shape, SwShape& sdata); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index eda12cc..c9df96f 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } -void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); @@ -90,7 +90,7 @@ void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) assert(sdata); } - if (flags == UpdateFlag::None) return nullptr; + if (flags == RenderUpdateFlag::None) return sdata; //invisible? size_t alpha; @@ -98,13 +98,14 @@ void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags) if (alpha == 0) return sdata; //TODO: Threading - if (flags & UpdateFlag::Path) { + if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; if (!shapeTransformOutline(shape, *sdata)) return sdata; SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; if (!shapeGenRle(shape, *sdata, clip)) return sdata; + shapeDelOutline(*sdata); } return sdata; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index ce87fa9..b299d70 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod public: Surface surface; - void* prepare(const Shape& shape, void* data, UpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 5a1c6c3..03be175 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -211,26 +211,57 @@ void _deleteRle(SwShape& sdata) } -void _deleteOutline(SwShape& sdata) -{ - if (!sdata.outline) return; - - SwOutline* outline = sdata.outline; - if (outline->cntrs) free(outline->cntrs); - if (outline->pts) free(outline->pts); - if (outline->types) free(outline->types); - free(outline); - - sdata.outline = nullptr; -} - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ bool shapeTransformOutline(const Shape& shape, SwShape& sdata) { - //TODO: + constexpr auto PI = 3.141592f; + + auto degree = shape.rotate(); + auto scale = shape.scale(); + bool rotateOn = false; + bool scaleOn = false; + + if (fabsf(degree) > FLT_EPSILON) rotateOn = true; + if (fabsf(scale - 1) > FLT_EPSILON) scaleOn = true; + + if (!rotateOn && !scaleOn) return true; + + auto outline = sdata.outline; + assert(outline); + + float x, y, w, h; + shape.bounds(x, y, w, h); + + auto cx = x + w * 0.5f; + auto cy = y + h * 0.5f; + + float radian, cosVal, sinVal; + if (rotateOn) { + radian = degree / 180.0f * PI; + cosVal = cosf(radian); + sinVal = sinf(radian); + } + + for(size_t i = 0; i < outline->ptsCnt; ++i) { + auto dx = static_cast(outline->pts[i].x >> 6) - cx; + auto dy = static_cast(outline->pts[i].y >> 6) - cy; + if (rotateOn) { + auto tx = (cosVal * dx - sinVal * dy); + auto ty = (sinVal * dx + cosVal * dy); + dx = tx; + dy = ty; + } + if (scaleOn) { + dx *= scale; + dy *= scale; + } + auto pt = Point{dx + cx, dy + cy}; + outline->pts[i] = TO_SWPOINT(&pt); + } + return true; } @@ -246,7 +277,6 @@ bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) (sdata.bbox.min.y + sdata.bbox.max.y < 0)) goto end; sdata.rle = rleRender(sdata, clip); - _deleteOutline(sdata); end: if (sdata.rle) return true; @@ -254,9 +284,23 @@ end: } +void shapeDelOutline(SwShape& sdata) +{ + if (!sdata.outline) return; + + SwOutline* outline = sdata.outline; + if (outline->cntrs) free(outline->cntrs); + if (outline->pts) free(outline->pts); + if (outline->types) free(outline->types); + free(outline); + + sdata.outline = nullptr; +} + + void shapeReset(SwShape& sdata) { - _deleteOutline(sdata); + shapeDelOutline(sdata); _deleteRle(sdata); _initBBox(sdata); } @@ -277,7 +321,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) auto outlinePtsCnt = 0; auto outlineCntrsCnt = 0; - for (auto i = 0; i < cmdCnt; ++i) { + for (size_t i = 0; i < cmdCnt; ++i) { switch(*(cmds + i)) { case PathCommand::Close: { ++outlinePtsCnt; @@ -311,7 +355,6 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) cout << "Outline was already allocated? How?" << endl; } - //TODO: Probabry we can copy pts from shape directly. _growOutlinePoint(*outline, outlinePtsCnt); _growOutlineContour(*outline, outlineCntrsCnt); diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 5d61991..9e8662b 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -28,12 +28,13 @@ struct Surface size_t w, h; }; +enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8}; + class RenderMethod { public: - enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 }; virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, UpdateFlag flags) = 0; + virtual void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) = 0; virtual bool dispose(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index bf937a2..0be6f4d 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -82,4 +82,16 @@ int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept return 0; } + +float Scene::scale() const noexcept +{ + return 0; +} + + +float Scene::rotate() const noexcept +{ + return 0; +} + #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 9c41c08..17e3a27 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -44,6 +44,7 @@ struct Shape::Impl float scale = 1; float rotate = 0; void *edata = nullptr; //engine data + size_t flag = RenderUpdateFlag::None; Impl() : path(new ShapePath) { @@ -55,14 +56,6 @@ struct Shape::Impl if (stroke) delete(stroke); if (fill) delete(fill); } - - bool update() - { - if (path->scale(scale)) scale = 1; - if (path->rotate(rotate)) rotate = 0; - - return true; - } }; @@ -99,10 +92,10 @@ int Shape::update(RenderMethod* engine) noexcept auto impl = pImpl.get(); assert(impl); - if (!impl->update()) return -1; - impl->edata = engine->prepare(*this, impl->edata, RenderMethod::UpdateFlag::All); + impl->edata = engine->prepare(*this, impl->edata, static_cast(impl->flag)); + impl->flag = RenderUpdateFlag::None; if (impl->edata) return 0; - return - 1; + return -1; } @@ -113,11 +106,13 @@ int Shape::reset() noexcept impl->path->reset(); + impl->flag |= RenderUpdateFlag::Path; + return 0; } -int Shape::pathCommands(const PathCommand** cmds) const noexcept +size_t Shape::pathCommands(const PathCommand** cmds) const noexcept { auto impl = pImpl.get(); assert(impl && impl->path && cmds); @@ -128,7 +123,7 @@ int Shape::pathCommands(const PathCommand** cmds) const noexcept } -int Shape::pathCoords(const Point** pts) const noexcept +size_t Shape::pathCoords(const Point** pts) const noexcept { auto impl = pImpl.get(); assert(impl && impl->path && pts); @@ -150,6 +145,8 @@ int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, impl->path->grow(cmdCnt, ptsCnt); impl->path->append(cmds, cmdCnt, pts, ptsCnt); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -161,6 +158,8 @@ int Shape::moveTo(float x, float y) noexcept impl->path->moveTo(x, y); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -172,6 +171,8 @@ int Shape::lineTo(float x, float y) noexcept impl->path->lineTo(x, y); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -183,6 +184,8 @@ int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -194,6 +197,8 @@ int Shape::close() noexcept impl->path->close(); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -214,6 +219,8 @@ int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexce impl->path->cubicTo(cx - radiusW, cy - halfKappaH, cx - halfKappaW, cy - radiusH, cx, cy - radiusH); impl->path->close(); + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -253,6 +260,8 @@ int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) no impl->path->close(); } + impl->flag |= RenderUpdateFlag::Path; + return 0; } @@ -266,6 +275,7 @@ int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept impl->color[1] = g; impl->color[2] = b; impl->color[3] = a; + impl->flag |= RenderUpdateFlag::Fill; return 0; } @@ -287,12 +297,13 @@ int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept int Shape::scale(float factor) noexcept { - if (factor < FLT_EPSILON || fabsf(factor - 1) <= FLT_EPSILON) return -1; - auto impl = pImpl.get(); assert(impl); - impl->scale *= factor; + if (fabsf(factor) < FLT_EPSILON || fabsf(factor - impl->scale) <= FLT_EPSILON) return -1; + + impl->scale = factor; + impl->flag |= RenderUpdateFlag::Transform; return 0; } @@ -300,12 +311,13 @@ int Shape::scale(float factor) noexcept int Shape::rotate(float degree) noexcept { - if (fabsf(degree) <= FLT_EPSILON) return -1; - auto impl = pImpl.get(); assert(impl); - impl->rotate += degree; + if (fabsf(degree - impl->rotate) <= FLT_EPSILON) return -1; + + impl->rotate = degree; + impl->flag |= RenderUpdateFlag::Transform; return 0; } @@ -321,4 +333,22 @@ int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept return 0; } + +float Shape::scale() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return impl->scale; +} + + +float Shape::rotate() const noexcept +{ + auto impl = pImpl.get(); + assert(impl); + + return impl->rotate; +} + #endif //_TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 9c42829..9dafdf9 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -134,49 +134,6 @@ struct ShapePath return true; } - - bool rotate(float degree) - { - constexpr auto PI = 3.141592f; - - if (fabsf(degree) <= FLT_EPSILON) return false; - - float x, y, w, h; - if (!bounds(x, y, w, h)) return false; - - auto radian = degree / 180.0f * PI; - auto cx = x + w * 0.5f; - auto cy = y + h * 0.5f; - auto cosVal = cosf(radian); - auto sinVal = sinf(radian); - - for(size_t i = 0; i < ptsCnt; ++i) { - auto dx = pts[i].x - cx; - auto dy = pts[i].y - cy; - pts[i].x = (cosVal * dx - sinVal * dy) + cx; - pts[i].y = (sinVal * dx + cosVal * dy) + cy; - } - - return true; - } - - bool scale(float factor) - { - if (fabsf(factor - 1) <= FLT_EPSILON) return false; - - float x, y, w, h; - if (!bounds(x, y, w, h)) return false; - - auto cx = x + w * 0.5f; - auto cy = y + h * 0.5f; - - for(size_t i = 0; i < ptsCnt; ++i) { - pts[i].x = (pts[i].x - cx) * factor + cx; - pts[i].y = (pts[i].y - cy) * factor + cy; - } - - return true; - } }; #endif //_TVG_SHAPE_PATH_CPP_ diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 1888de4..9a6152c 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -24,6 +24,8 @@ void tvgtest() pShape = shape.get(); shape->appendRect(-100, -100, 200, 200, 0); + + //fill and rotate properties will be retained shape->fill(127, 255, 255, 255); shape->rotate(45); canvas->push(move(shape)); @@ -42,11 +44,6 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->reset(); //reset path pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); - - /* rotate, scale won't be retained, when you call reset() for the shape, these values will be reset as well. - These are working in fire & forget method, it actually modify the path data for avoiding compuatation every frames. - Thus user needs to keep the last values to understand the final accumulated values. */ - pShape->rotate(45); pShape->scale(1 - 0.75 * progress); //Update shape for drawing (this may work asynchronously) -- 2.7.4