mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 21:53:41 +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
|
testMultiShapes
|
||||||
testMergeShapes
|
testMergeShapes
|
||||||
testBoundary
|
testBoundary
|
||||||
|
testPath
|
||||||
|
|
|
@ -121,6 +121,7 @@ public:
|
||||||
|
|
||||||
int appendRect(float x, float y, float w, float h, float cornerRadius) 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 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;
|
int fill(size_t r, size_t g, size_t b, size_t a) noexcept;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
#include <string.h>
|
||||||
#include "tizenvg.h"
|
#include "tizenvg.h"
|
||||||
#include "tvgRenderCommon.h"
|
#include "tvgRenderCommon.h"
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,9 @@ int ShapeNode::clear() noexcept
|
||||||
auto impl = pImpl.get();
|
auto impl = pImpl.get();
|
||||||
assert(impl);
|
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
|
int ShapeNode::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept
|
||||||
{
|
{
|
||||||
auto impl = pImpl.get();
|
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 halfKappaW = radiusW * PATH_KAPPA;
|
||||||
auto halfKappaH = radiusH * 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->moveTo(cx, cy - radiusH);
|
||||||
impl->path->cubicTo(cx + halfKappaW, cy - radiusH, cx + radiusW, cy - halfKappaH, cx + radiusW, cy);
|
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);
|
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
|
//rectangle
|
||||||
if (cornerRadius == 0) {
|
if (cornerRadius == 0) {
|
||||||
impl->path->reserve(5, 4);
|
impl->path->grow(5, 4);
|
||||||
impl->path->moveTo(x, y);
|
impl->path->moveTo(x, y);
|
||||||
impl->path->lineTo(x + w, y);
|
impl->path->lineTo(x + w, y);
|
||||||
impl->path->lineTo(x + w, y + h);
|
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);
|
return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius, cornerRadius);
|
||||||
} else {
|
} else {
|
||||||
auto halfKappa = cornerRadius * 0.5;
|
auto halfKappa = cornerRadius * 0.5;
|
||||||
impl->path->reserve(10, 17);
|
impl->path->grow(10, 17);
|
||||||
impl->path->moveTo(x + cornerRadius, y);
|
impl->path->moveTo(x + cornerRadius, y);
|
||||||
impl->path->lineTo(x + w - 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);
|
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);
|
if (pts) delete(pts);
|
||||||
}
|
}
|
||||||
|
|
||||||
int reserveCmd(size_t cmdCnt)
|
void reserveCmd(size_t cmdCnt)
|
||||||
{
|
{
|
||||||
if (cmdCnt > reservedCmdCnt) {
|
if (cmdCnt <= reservedCmdCnt) return;
|
||||||
reservedCmdCnt = cmdCnt;
|
reservedCmdCnt = cmdCnt;
|
||||||
cmds = static_cast<PathCommand*>(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt));
|
cmds = static_cast<PathCommand*>(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt));
|
||||||
assert(cmds);
|
assert(cmds);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int reservePts(size_t ptsCnt)
|
void reservePts(size_t ptsCnt)
|
||||||
{
|
{
|
||||||
if (ptsCnt > reservedPtsCnt) {
|
if (ptsCnt <= reservedPtsCnt) return;
|
||||||
reservedPtsCnt = ptsCnt;
|
reservedPtsCnt = ptsCnt;
|
||||||
pts = static_cast<Point*>(realloc(pts, sizeof(Point) * reservedPtsCnt));
|
pts = static_cast<Point*>(realloc(pts, sizeof(Point) * reservedPtsCnt));
|
||||||
assert(pts);
|
assert(pts);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int reserve(size_t cmdCnt, size_t ptsCnt)
|
void reserve(size_t cmdCnt, size_t ptsCnt)
|
||||||
{
|
{
|
||||||
reserveCmd(cmdCnt);
|
reserveCmd(cmdCnt);
|
||||||
reservePts(ptsCnt);
|
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;
|
cmdCnt = 0;
|
||||||
ptsCnt = 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 (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
||||||
if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
|
if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
|
||||||
|
|
||||||
cmds[cmdCnt++] = PathCommand::MoveTo;
|
cmds[cmdCnt++] = PathCommand::MoveTo;
|
||||||
pts[ptsCnt++] = {x, y};
|
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 (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
||||||
if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
|
if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
|
||||||
|
|
||||||
cmds[cmdCnt++] = PathCommand::LineTo;
|
cmds[cmdCnt++] = PathCommand::LineTo;
|
||||||
pts[ptsCnt++] = {x, y};
|
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 (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
||||||
if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2);
|
if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2);
|
||||||
|
@ -107,39 +110,12 @@ struct ShapePath
|
||||||
pts[ptsCnt++] = {cx1, cy1};
|
pts[ptsCnt++] = {cx1, cy1};
|
||||||
pts[ptsCnt++] = {cx2, cy2};
|
pts[ptsCnt++] = {cx2, cy2};
|
||||||
pts[ptsCnt++] = {x, y};
|
pts[ptsCnt++] = {x, y};
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void close()
|
||||||
int close()
|
|
||||||
{
|
{
|
||||||
if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
|
||||||
cmds[cmdCnt++] = PathCommand::Close;
|
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 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 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 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 <tizenvg.h>
|
||||||
|
#include <Elementary.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -7,7 +8,7 @@ using namespace std;
|
||||||
|
|
||||||
static uint32_t buffer[WIDTH * HEIGHT];
|
static uint32_t buffer[WIDTH * HEIGHT];
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
void tvgtest()
|
||||||
{
|
{
|
||||||
//Initialize TizenVG Engine
|
//Initialize TizenVG Engine
|
||||||
tvg::Engine::init();
|
tvg::Engine::init();
|
||||||
|
@ -15,25 +16,114 @@ int main(int argc, char **argv)
|
||||||
//Create a Canvas
|
//Create a Canvas
|
||||||
auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT);
|
auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT);
|
||||||
|
|
||||||
//Prepare Path
|
/* Star */
|
||||||
auto path = tvg::Path::gen();
|
|
||||||
path.reserve(cmdCnt, ptCnt); //command count, points count
|
//Prepare Path Commands
|
||||||
path.moveTo(...);
|
tvg::PathCommand cmds[11];
|
||||||
path.lineTo(...);
|
cmds[0] = tvg::PathCommand::MoveTo;
|
||||||
path.cubicTo(...);
|
cmds[1] = tvg::PathCommand::LineTo;
|
||||||
path.close();
|
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();
|
auto shape1 = tvg::ShapeNode::gen();
|
||||||
shape1->path(move(path)); //migrate owner otherwise,
|
shape1->appendPath(cmds, 11, pts, 10); //copy path data
|
||||||
shape1->path(path.get()); //copy raw data directly for performance
|
|
||||||
shape1->fill(0, 255, 0, 255);
|
shape1->fill(0, 255, 0, 255);
|
||||||
|
|
||||||
//Draw the Shape onto the Canvas
|
|
||||||
canvas->push(move(shape1));
|
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->draw();
|
||||||
canvas->sync();
|
canvas->sync();
|
||||||
|
|
||||||
//Terminate TizenVG Engine
|
//Terminate TizenVG Engine
|
||||||
tvg::Engine::term();
|
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