From 809dfd8644c4b41a0958a212f24d2daa180bd51c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 27 Apr 2020 01:52:44 +0900 Subject: [PATCH 01/16] canvas: add reserve() method. This allocates nodes slots in advance to avoid memory grow & copy. it will be benefit if you know how many shapes will be used in your canvas. Change-Id: I7d93d166c9c054078bd86593d3471a2ade3671ee --- inc/tizenvg.h | 1 + src/lib/tvgCanvas.cpp | 8 ++++++++ test/testMultiShapes.cpp | 2 +- test/testShape.cpp | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index babca5d..1aee6bb 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -90,6 +90,7 @@ public: Canvas(RenderMethod*); virtual ~Canvas(); + int reserve(size_t n); virtual int push(std::unique_ptr paint) noexcept; virtual int clear() noexcept; virtual int update() noexcept; diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 3bde24f..96b58e0 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -120,6 +120,14 @@ Canvas::~Canvas() } +int Canvas::reserve(size_t n) +{ + auto impl = pImpl.get(); + assert(impl); + return impl->reserve(n); +} + + int Canvas::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 94d3c31..6fc0469 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -15,7 +15,7 @@ void tvgtest() //Create a Canvas auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - //canvas->reserve(2); //reserve 2 shape nodes (optional) + canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle auto shape1 = tvg::ShapeNode::gen(); diff --git a/test/testShape.cpp b/test/testShape.cpp index c806d99..b7fca2f 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -18,7 +18,7 @@ void tvgtest() //Prepare a Shape (Rectangle) auto shape1 = tvg::ShapeNode::gen(); - shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius + shape1->appendRect(100, 100, 400, 400, 0); //x, y, w, h, cornerRadius shape1->fill(255, 0, 0, 255); //r, g, b, a /* Push the shape into the Canvas drawing list -- 2.7.4 From c813de45caa5f9c9e342be1dfea82ec450d09eda Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 27 Apr 2020 01:59:49 +0900 Subject: [PATCH 02/16] update gitignore file Change-Id: I0b245f1177e3df04ddc6f345213bbb1207d3e950 --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 45329ec..a6a008a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ build .vscode *.swp testShape +testMultiShapes +testMergeShapes -- 2.7.4 From 5120a7ae125db724c7ea32a77b0ed4819b57886a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 27 Apr 2020 02:00:38 +0900 Subject: [PATCH 03/16] canvas: correct convention add missing noexcept option. Change-Id: I14eacb0fdb2c9bd40e365bf81bb5cc0b73239ffe --- inc/tizenvg.h | 2 +- src/lib/tvgCanvas.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 1aee6bb..c53a5dc 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -90,7 +90,7 @@ public: Canvas(RenderMethod*); virtual ~Canvas(); - int reserve(size_t n); + int reserve(size_t n) noexcept; virtual int push(std::unique_ptr paint) noexcept; virtual int clear() noexcept; virtual int update() noexcept; diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 96b58e0..3723083 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -120,7 +120,7 @@ Canvas::~Canvas() } -int Canvas::reserve(size_t n) +int Canvas::reserve(size_t n) noexcept { auto impl = pImpl.get(); assert(impl); -- 2.7.4 From 46ba3352a8313b602c04da9ddcf8dea955c485b6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 00:54:41 +0900 Subject: [PATCH 04/16] sw_engine: case cover out of surface boundary. Also added surface boundary test code. Change-Id: Ib4c327d12ce52d506f1b8a566ffa48e5b5b8c03e --- .gitignore | 1 + src/lib/sw_engine/tvgSwCommon.h | 12 ++++-- src/lib/sw_engine/tvgSwRaster.cpp | 3 +- src/lib/sw_engine/tvgSwRenderer.cpp | 5 ++- src/lib/sw_engine/tvgSwRle.cpp | 42 ++++++++++++------ src/lib/sw_engine/tvgSwShape.cpp | 12 +++++- test/makefile | 1 + test/testBoundary.cpp | 86 +++++++++++++++++++++++++++++++++++++ 8 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 test/testBoundary.cpp diff --git a/.gitignore b/.gitignore index a6a008a..bbd3f8e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build testShape testMultiShapes testMergeShapes +testBoundary diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4b6f820..012f968 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -49,6 +49,11 @@ struct SwPoint } }; +struct SwSize +{ + SwCoord w, h; +}; + struct SwOutline { size_t* cntrs; //the contour end points @@ -63,7 +68,7 @@ struct SwOutline struct SwSpan { - uint16_t x, y; + int16_t x, y; uint16_t len; uint8_t coverage; }; @@ -90,10 +95,9 @@ 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); +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip); bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); - -SwRleData* rleRender(const SwShape& sdata); +SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, size_t color); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 2e43a44..a71c443 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -23,13 +23,14 @@ bool rasterShape(Surface& surface, SwShape& sdata, size_t color) { SwRleData* rle = sdata.rle; - assert(rle); + if (!rle) return false; auto stride = surface.stride; auto span = rle->spans; 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; } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 425afab..ae43735 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -55,7 +55,6 @@ bool SwRenderer::render(const ShapeNode& shape, void *data) //invisible? size_t r, g, b, a; shape.fill(&r, &g, &b, &a); - if (a == 0) return true; //TODO: Threading return rasterShape(surface, *sdata, COLOR(r, g, b, a)); @@ -92,7 +91,9 @@ void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; if (!shapeTransformOutline(shape, *sdata)) return sdata; - if (!shapeGenRle(shape, *sdata)) return sdata; + + SwSize clip = {static_cast(surface.stride), static_cast(surface.height)}; + if (!shapeGenRle(shape, *sdata, clip)) return sdata; } return sdata; diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index f17c684..3991fff 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -84,6 +84,8 @@ struct RleWorker Cell** yCells; SwCoord yCnt; + SwSize clip; + bool invalid; }; @@ -161,6 +163,13 @@ static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count) static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount) { + x += rw.cellMin.x; + y += rw.cellMin.y; + + //Clip Y range + if (y < 0) return; + if (y >= rw.clip.h) return; + /* compute the coverage line's coverage, depending on the outline fill rule */ /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ auto coverage = static_cast(area >> (PIXEL_BITS * 2 + 1 - 8)); //range 0 - 256 @@ -176,9 +185,6 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor if (coverage >= 256) coverage = 255; } - x += rw.cellMin.x; - y += rw.cellMin.y; - //span has ushort coordinates. check limit overflow if (x >= SHRT_MAX) { cout << "x(" << x << ") coordinate overflow!" << endl; @@ -197,7 +203,13 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor //see whether we can add this span to the current list if ((count > 0) && (rw.ySpan == y) && (span->x + span->len == x) && (span->coverage == coverage)) { - span->len = span->len + acount; + + //Clip x range + SwCoord xOver = 0; + if (x + acount >= rw.clip.w) xOver -= (x + acount - rw.clip.w); + if (x < 0) xOver += x; + + span->len += (acount + xOver) - 1; return; } @@ -211,10 +223,21 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor assert(span); } + //Clip x range + SwCoord xOver = 0; + if (x + acount >= rw.clip.w) xOver -= (x + acount - rw.clip.w); + if (x < 0) { + xOver += x; + x = 0; + } + + //Nothing to draw + if (acount + xOver <= 0) return; + //add a span to the current list span->x = x; span->y = y; - span->len = acount; + span->len = (acount + xOver); span->coverage = coverage; ++rw.spansCnt; } @@ -646,16 +669,13 @@ static bool _genRle(RleWorker& rw) /* External Class Implementation */ /************************************************************************/ -SwRleData* rleRender(const SwShape& sdata) +SwRleData* rleRender(const SwShape& sdata, const SwSize& clip) { constexpr auto RENDER_POOL_SIZE = 16384L; constexpr auto BAND_SIZE = 40; auto outline = sdata.outline; assert(outline); - - if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return nullptr; - assert(outline->cntrs && outline->pts); assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1); @@ -680,11 +700,10 @@ SwRleData* rleRender(const SwShape& sdata) rw.outline = outline; rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; + rw.clip = clip; rw.rle = reinterpret_cast(calloc(1, sizeof(SwRleData))); assert(rw.rle); - //printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.cellMin.x, rw.cellMin.y, rw.cellMax.x, rw.cellMax.y, rw.cellXCnt, rw.cellYCnt, rw.bandSize); - //Generate RLE Band bands[BAND_SIZE]; Band* band; @@ -717,7 +736,6 @@ SwRleData* rleRender(const SwShape& sdata) auto cellEnd = rw.bufferSize; cellEnd -= cellEnd % sizeof(Cell); -//printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod); auto cellsMax = reinterpret_cast((char*)rw.buffer + cellEnd); rw.cells = reinterpret_cast((char*)rw.buffer + cellStart); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index e725e30..1f24a63 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -235,11 +235,19 @@ bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) } -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip) { + if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) goto end; if (!_updateBBox(sdata)) goto end; - sdata.rle = rleRender(sdata); + + //Check boundary + if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) || + (sdata.bbox.min.x + sdata.bbox.max.x < 0) || + (sdata.bbox.min.y + sdata.bbox.max.y < 0)) goto end; + + sdata.rle = rleRender(sdata, clip); _deleteOutline(sdata); + end: if (sdata.rle) return true; return false; diff --git a/test/makefile b/test/makefile index bb80729..1bab747 100644 --- a/test/makefile +++ b/test/makefile @@ -2,3 +2,4 @@ all: gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` 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` diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp new file mode 100644 index 0000000..473fd59 --- /dev/null +++ b/test/testBoundary.cpp @@ -0,0 +1,86 @@ +#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); + canvas->reserve(5); //reserve 5 shape nodes (optional) + + //Prepare Shape1 + auto shape1 = tvg::ShapeNode::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(); + shape2->appendRect(-100, -100, 250, 250, 50); + shape2->fill(0, 0, 255, 255); + canvas->push(move(shape2)); + + //Prepare Shape3 + auto shape3 = tvg::ShapeNode::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(); + shape4->appendCircle(800, 100, 200, 200); + shape4->fill(255, 255, 0, 255); + canvas->push(move(shape4)); + + //Prepare Shape5 + auto shape5 = tvg::ShapeNode::gen(); + shape5->appendCircle(200, 650, 250, 200); + shape5->fill(0, 0, 0, 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(); +} -- 2.7.4 From e0ecd680a02ccf9e3ef46c4c82b2336d9509426f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 15:41:16 +0900 Subject: [PATCH 05/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 06/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 07/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 08/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 09/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 10/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 11/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 12/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 13/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 14/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 15/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 16/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