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
This commit is contained in:
Hermet Park 2020-04-30 18:31:51 +09:00
parent e0ecd680a0
commit 9b8ab42e54
7 changed files with 158 additions and 72 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@ testShape
testMultiShapes
testMergeShapes
testBoundary
testPath

View 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;

View file

@ -22,6 +22,7 @@
#include <vector>
#include <math.h>
#include <float.h>
#include <string.h>
#include "tizenvg.h"
#include "tvgRenderCommon.h"

View 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);

View file

@ -40,65 +40,68 @@ struct ShapePath
if (pts) delete(pts);
}
int reserveCmd(size_t cmdCnt)
void reserveCmd(size_t cmdCnt)
{
if (cmdCnt > reservedCmdCnt) {
if (cmdCnt <= reservedCmdCnt) return;
reservedCmdCnt = cmdCnt;
cmds = static_cast<PathCommand*>(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt));
assert(cmds);
}
return 0;
}
int reservePts(size_t ptsCnt)
void reservePts(size_t ptsCnt)
{
if (ptsCnt > reservedPtsCnt) {
if (ptsCnt <= reservedPtsCnt) return;
reservedPtsCnt = ptsCnt;
pts = static_cast<Point*>(realloc(pts, sizeof(Point) * reservedPtsCnt));
assert(pts);
}
return 0;
}
int reserve(size_t cmdCnt, size_t ptsCnt)
void reserve(size_t cmdCnt, size_t ptsCnt)
{
reserveCmd(cmdCnt);
reservePts(ptsCnt);
return 0;
}
int clear()
void grow(size_t cmdCnt, size_t ptsCnt)
{
reserveCmd(this->cmdCnt + cmdCnt);
reservePts(this->ptsCnt + ptsCnt);
}
void clear()
{
cmdCnt = 0;
ptsCnt = 0;
return 0;
}
int moveTo(float x, float y)
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;
}
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;
}
};

View 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`

View 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();
}