common shape: support path appending 05/232305/2
authorHermet Park <chuneon.park@samsung.com>
Thu, 30 Apr 2020 09:31:51 +0000 (18:31 +0900)
committerHermet Park <chuneon.park@samsung.com>
Thu, 30 Apr 2020 09:33:01 +0000 (18:33 +0900)
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
inc/tizenvg.h
src/lib/tvgCommon.h
src/lib/tvgShapeNode.cpp
src/lib/tvgShapePath.h
test/makefile
test/testPath.cpp

index bbd3f8e..ddc6523 100644 (file)
@@ -5,3 +5,4 @@ testShape
 testMultiShapes
 testMergeShapes
 testBoundary
+testPath
index c53a5dc..89db3f5 100644 (file)
@@ -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;
 
index 2653d3a..c3f0c56 100644 (file)
@@ -22,6 +22,7 @@
 #include <vector>
 #include <math.h>
 #include <float.h>
+#include <string.h>
 #include "tizenvg.h"
 #include "tvgRenderCommon.h"
 
index a6e4511..0c01c0f 100644 (file)
@@ -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);
index 6fda0f0..f4fee18 100644 (file)
@@ -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<PathCommand*>(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt));
-            assert(cmds);
-        }
-        return 0;
+        if (cmdCnt <= reservedCmdCnt) return;
+        reservedCmdCnt = cmdCnt;
+        cmds = static_cast<PathCommand*>(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<Point*>(realloc(pts, sizeof(Point) * reservedPtsCnt));
-            assert(pts);
-        }
-        return 0;
+        if (ptsCnt <= reservedPtsCnt) return;
+        reservedPtsCnt = ptsCnt;
+        pts = static_cast<Point*>(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;
     }
 };
 
index 1bab747..e213907 100644 (file)
@@ -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`
index e260682..a75c7f7 100644 (file)
@@ -1,4 +1,5 @@
 #include <tizenvg.h>
+#include <Elementary.h>
 
 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();
+}