mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
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:
parent
e0ecd680a0
commit
9b8ab42e54
7 changed files with 158 additions and 72 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,3 +5,4 @@ testShape
|
|||
testMultiShapes
|
||||
testMergeShapes
|
||||
testBoundary
|
||||
testPath
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <vector>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include "tizenvg.h"
|
||||
#include "tvgRenderCommon.h"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue