testStroke
testStrokeLine
testLinearGradient
+testRadialGradient
struct SwFill
{
+ struct SwLinear {
+ float dx, dy;
+ float len;
+ float offset;
+ };
+
+ struct SwRadial {
+ float cx, cy;
+ float a;
+ float inv2a;
+ };
+
+ union {
+ SwLinear linear;
+ SwRadial radial;
+ };
+
uint32_t* ctable;
- float x1, y1, x2, y2;
- float dx, dy;
- float len;
- float offset;
FillSpread spread;
bool translucent;
};
bool fillGenColorTable(SwFill* fill, const Fill* fdata);
void fillReset(SwFill* fill, const Fill* fdata);
void fillFree(SwFill* fill);
-void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len);
+void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len);
+void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len);
SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip);
void rleFree(SwRleData* rle);
-bool rasterGradientShape(Surface& surface, SwShape& shape);
+bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id);
bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
bool rasterStroke(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
#define FIXPT_SIZE (1<<FIXPT_BITS)
-static bool _updateColorTable(SwFill* fill, const LinearGradient* linear)
+static bool _updateColorTable(SwFill* fill, const Fill* fdata)
{
- assert(fill && linear);
+ assert(fill && fdata);
if (!fill->ctable) {
fill->ctable = static_cast<uint32_t*>(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t)));
}
const Fill::ColorStop* colors;
- auto cnt = linear->colorStops(&colors);
+ auto cnt = fdata->colorStops(&colors);
if (cnt == 0 || !colors) return false;
auto pColors = colors;
{
assert(fill && linear);
- if (linear->linear(&fill->x1, &fill->y1, &fill->x2, &fill->y2) != Result::Success) return false;
+ float x1, x2, y1, y2;
+ if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false;
- fill->dx = fill->x2 - fill->x1;
- fill->dy = fill->y2 - fill->y1;
- fill->len = fill->dx * fill->dx + fill->dy * fill->dy;
- fill->offset = 0;
+ fill->linear.dx = x2 - x1;
+ fill->linear.dy = y2 - y1;
+ fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy;
- if (fill->len < FLT_EPSILON) return true;
+ if (fill->linear.len < FLT_EPSILON) return true;
- fill->dx /= fill->len;
- fill->dy /= fill->len;
- fill->offset = -fill->dx * fill->x1 - fill->dy * fill->y1;
+ fill->linear.dx /= fill->linear.len;
+ fill->linear.dy /= fill->linear.len;
+ fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1;
return _updateColorTable(fill, linear);
}
{
assert(fill && radial);
- return true;
+ float radius;
+ if (radial->radial(&fill->radial.cx, &fill->radial.cy, &radius) != Result::Success) return false;
+ if (radius < FLT_EPSILON) return true;
+
+ fill->radial.a = radius * radius;
+ fill->radial.inv2a = pow(1 / (2 * fill->radial.a), 2);
+
+ return _updateColorTable(fill, radial);
}
/* External Class Implementation */
/************************************************************************/
-void fillFetch(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len)
+void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len)
+{
+ if (fill->radial.a < FLT_EPSILON) return;
+
+ //TODO: Rotation???
+ auto rx = x + 0.5f - fill->radial.cx;
+ auto ry = y + 0.5f - fill->radial.cy;
+ auto inv2a = fill->radial.inv2a;
+ auto rxy = rx * rx + ry * ry;
+ auto rxryPlus = 2 * rx;
+ auto det = (-4 * fill->radial.a * -rxy) * inv2a;
+ auto detDelta = (4 * fill->radial.a * (rxryPlus + 1.0f)) * inv2a;
+ auto detDelta2 = (4 * fill->radial.a * 2.0f) * inv2a;
+
+ for (uint32_t i = 0 ; i < len ; ++i)
+ {
+ *dst = _pixel(fill, sqrt(det));
+ ++dst;
+ det += detDelta;
+ detDelta += detDelta2;
+ }
+}
+
+
+void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len)
{
- assert(fill->len > 0);
+ if (fill->linear.len < FLT_EPSILON) return;
//TODO: Rotation???
auto rx = x + 0.5f;
auto ry = y + 0.5f;
- auto t = (fill->dx * rx + fill->dy * ry + fill->offset) * (GRADIENT_STOP_SIZE - 1);
- auto inc = (fill->dx) * (GRADIENT_STOP_SIZE - 1);
+ auto t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1);
+ auto inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1);
if (fabsf(inc) < FLT_EPSILON) {
auto color = _fixedPixel(fill, static_cast<uint32_t>(t * FIXPT_SIZE));
}
-static bool _rasterGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill)
+static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill)
{
if (!rle || !fill) return false;
//Translucent Gradient
if (fill->translucent) {
- uint32_t tmp;
for (uint32_t i = 0; i < rle->size; ++i) {
auto dst = &surface.buffer[span->y * stride + span->x];
- fillFetch(fill, buf, span->y, span->x, span->len);
+ fillFetchLinear(fill, buf, span->y, span->x, span->len);
if (span->coverage == 255) {
for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i]));
}
} else {
for (uint32_t i = 0; i < span->len; ++i) {
- tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage);
+ auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage);
dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp));
}
}
for (uint32_t i = 0; i < rle->size; ++i) {
auto dst = &surface.buffer[span->y * stride + span->x];
if (span->coverage == 255) {
- fillFetch(fill, dst, span->y, span->x, span->len);
+ fillFetchLinear(fill, dst, span->y, span->x, span->len);
} else {
- fillFetch(fill, buf, span->y, span->x, span->len);
+ fillFetchLinear(fill, buf, span->y, span->x, span->len);
+ auto ialpha = 255 - span->coverage;
+ for (uint32_t i = 0; i < span->len; ++i) {
+ dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha);
+ }
+ }
+ ++span;
+ }
+ }
+ return true;
+}
+
+
+static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill)
+{
+ if (!rle || !fill) return false;
+
+ auto buf = static_cast<uint32_t*>(alloca(surface.w * sizeof(uint32_t)));
+ if (!buf) return false;
+
+ auto span = rle->spans;
+ auto stride = surface.stride;
+
+ //Translucent Gradient
+ if (fill->translucent) {
+ for (uint32_t i = 0; i < rle->size; ++i) {
+ auto dst = &surface.buffer[span->y * stride + span->x];
+ fillFetchRadial(fill, buf, span->y, span->x, span->len);
+ if (span->coverage == 255) {
+ for (uint32_t i = 0; i < span->len; ++i) {
+ dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i]));
+ }
+ } else {
+ for (uint32_t i = 0; i < span->len; ++i) {
+ auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage);
+ dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp));
+ }
+ }
+ ++span;
+ }
+ //Opaque Gradient
+ } else {
+ for (uint32_t i = 0; i < rle->size; ++i) {
+ auto dst = &surface.buffer[span->y * stride + span->x];
+ if (span->coverage == 255) {
+ fillFetchRadial(fill, dst, span->y, span->x, span->len);
+ } else {
+ fillFetchRadial(fill, buf, span->y, span->x, span->len);
auto ialpha = 255 - span->coverage;
for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha);
/* External Class Implementation */
/************************************************************************/
-bool rasterGradientShape(Surface& surface, SwShape& shape)
+bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id)
{
- return _rasterGradientRle(surface, shape.rle, shape.fill);
+ if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill);
+ return _rasterRadialGradientRle(surface, shape.rle, shape.fill);
}
uint8_t r, g, b, a;
- if (sdata.fill()) {
- rasterGradientShape(surface, *shape);
+ if (auto fill = sdata.fill()) {
+ rasterGradientShape(surface, *shape, fill->id());
} else {
sdata.fill(&r, &g, &b, &a);
if (a > 0) rasterSolidShape(surface, *shape, r, g, b, a);
gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
gcc -o testStrokeLine testStrokeLine.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
+ gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
--- /dev/null
+#include <tizenvg.h>
+#include <Elementary.h>
+
+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(3); //reserve 3 shape nodes (optional)
+
+ //Prepare Round Rectangle
+ auto shape1 = tvg::Shape::gen();
+ shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius
+
+ //RadialGradient
+ auto fill = tvg::RadialGradient::gen();
+ fill->radial(200, 200, 200);
+
+ //Linear Gradient Color Stops
+ tvg::Fill::ColorStop colorStops[2];
+ colorStops[0] = {0, 255, 255, 255, 255};
+ colorStops[1] = {1, 0, 0, 0, 255};
+
+ fill->colorStops(colorStops, 2);
+
+ shape1->fill(move(fill));
+ canvas->push(move(shape1));
+
+ //Prepare Circle
+ auto shape2 = tvg::Shape::gen();
+ shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH
+
+ //RadialGradient
+ auto fill2 = tvg::RadialGradient::gen();
+ fill2->radial(400, 400, 200);
+
+ //Linear Gradient Color Stops
+ tvg::Fill::ColorStop colorStops2[3];
+ colorStops2[0] = {0, 255, 0, 0, 255};
+ colorStops2[1] = {0.5, 255, 255, 0, 255};
+ colorStops2[2] = {1, 255, 255, 255, 255};
+
+ fill2->colorStops(colorStops2, 3);
+
+ shape2->fill(move(fill2));
+ canvas->push(move(shape2));
+
+
+ //Prepare Ellipse
+ auto shape3 = tvg::Shape::gen();
+ shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH
+
+ //RadialGradient
+ auto fill3 = tvg::RadialGradient::gen();
+ fill3->radial(600, 600, 150);
+
+ //Linear Gradient Color Stops
+ tvg::Fill::ColorStop colorStops3[4];
+ colorStops3[0] = {0, 0, 127, 0, 127};
+ colorStops3[1] = {0.25, 0, 170, 170, 170};
+ colorStops3[2] = {0.5, 200, 0, 200, 200};
+ colorStops3[3] = {1, 255, 255, 255, 255};
+
+ fill3->colorStops(colorStops3, 4);
+
+ shape3->fill(move(fill3));
+ canvas->push(move(shape3));
+
+ //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();
+}