--- /dev/null
+#include "Common.h"
+#include <fstream>
+
+/************************************************************************/
+/* Drawing Commands */
+/************************************************************************/
+
+uint32_t *data = nullptr;
+
+void tvgDrawCmds(tvg::Canvas* canvas)
+{
+ if (!canvas) return;
+
+ //Solid Rectangle
+ auto shape = tvg::Shape::gen();
+ shape->appendRect(0, 0, 400, 400, 0, 0);
+
+ //Mask
+ auto mask = tvg::Shape::gen();
+ mask->appendCircle(200, 200, 125, 125);
+ mask->fill(255, 0, 0, 255);
+
+ auto fill = tvg::LinearGradient::gen();
+ fill->linear(0, 0, 400, 400);
+ tvg::Fill::ColorStop colorStops[2];
+ colorStops[0] = {0,0,0,0,255};
+ colorStops[1] = {1,255,255,255,255};
+ fill->colorStops(colorStops,2);
+ shape->fill(move(fill));
+
+ shape->composite(move(mask), tvg::CompositeMethod::AlphaMask);
+ canvas->push(move(shape));
+
+//-------------------------------------------
+
+ //Star
+ auto shape1 = tvg::Shape::gen();
+ shape1->moveTo(599, 34);
+ shape1->lineTo(653, 143);
+ shape1->lineTo(774, 160);
+ shape1->lineTo(687, 244);
+ shape1->lineTo(707, 365);
+ shape1->lineTo(599, 309);
+ shape1->lineTo(497, 365);
+ shape1->lineTo(512, 245);
+ shape1->lineTo(426, 161);
+ shape1->lineTo(546, 143);
+ shape1->close();
+
+ //Mask
+ auto mask1 = tvg::Shape::gen();
+ mask1->appendCircle(600, 200, 125, 125);
+ mask1->fill(255, 0, 0, 255);
+
+ auto fill1 = tvg::LinearGradient::gen();
+ fill1->linear(400, 0, 800, 400);
+ tvg::Fill::ColorStop colorStops1[2];
+ colorStops1[0] = {0,0,0,0,255};
+ colorStops1[1] = {1,1,255,255,255};
+ fill1->colorStops(colorStops1,2);
+ shape1->fill(move(fill1));
+
+ shape1->composite(move(mask1), tvg::CompositeMethod::AlphaMask);
+ canvas->push(move(shape1));
+
+//-------------------------------------------
+
+ //Solid Rectangle
+ auto shape2 = tvg::Shape::gen();
+ shape2->appendRect(0, 400, 400, 400, 0, 0);
+
+ //Mask
+ auto mask2 = tvg::Shape::gen();
+ mask2->appendCircle(200, 600, 125, 125);
+ mask2->fill(255, 0, 0, 255);
+
+ auto fill2 = tvg::LinearGradient::gen();
+ fill2->linear(0, 400, 400, 800);
+ tvg::Fill::ColorStop colorStops2[2];
+ colorStops2[0] = {0,0,0,0,255};
+ colorStops2[1] = {1,255,255,255,255};
+ fill2->colorStops(colorStops2,2);
+ shape2->fill(move(fill2));
+
+ shape2->composite(move(mask2), tvg::CompositeMethod::InvAlphaMask);
+ canvas->push(move(shape2));
+
+//-------------------------------------------
+
+ // Star
+ auto shape3 = tvg::Shape::gen();
+ shape3->moveTo(599, 434);
+ shape3->lineTo(653, 543);
+ shape3->lineTo(774, 560);
+ shape3->lineTo(687, 644);
+ shape3->lineTo(707, 765);
+ shape3->lineTo(599, 709);
+ shape3->lineTo(497, 765);
+ shape3->lineTo(512, 645);
+ shape3->lineTo(426, 561);
+ shape3->lineTo(546, 543);
+ shape3->close();
+
+ //Mask
+ auto mask3 = tvg::Shape::gen();
+ mask3->appendCircle(600, 600, 125, 125);
+ mask3->fill(255, 0, 0, 255);
+
+ auto fill3 = tvg::LinearGradient::gen();
+ fill3->linear(400, 400, 800, 800);
+ tvg::Fill::ColorStop colorStops3[2];
+ colorStops3[0] = {0,0,0,0,255};
+ colorStops3[1] = {1,1,255,255,255};
+ fill3->colorStops(colorStops3,2);
+ shape3->fill(move(fill3));
+
+ shape3->composite(move(mask3), tvg::CompositeMethod::InvAlphaMask);
+ canvas->push(move(shape3));
+
+}
+
+
+/************************************************************************/
+/* Sw Engine Test Code */
+/************************************************************************/
+
+static unique_ptr<tvg::SwCanvas> swCanvas;
+
+void tvgSwTest(uint32_t* buffer)
+{
+ //Create a Canvas
+ swCanvas = tvg::SwCanvas::gen();
+ swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
+
+ /* Push the shape into the Canvas drawing list
+ When this shape is into the canvas list, the shape could update & prepare
+ internal data asynchronously for coming rendering.
+ Canvas keeps this shape node unless user call canvas->clear() */
+ tvgDrawCmds(swCanvas.get());
+}
+
+void drawSwView(void* data, Eo* obj)
+{
+ if (swCanvas->draw() == tvg::Result::Success) {
+ swCanvas->sync();
+ }
+}
+
+
+/************************************************************************/
+/* GL Engine Test Code */
+/************************************************************************/
+
+static unique_ptr<tvg::GlCanvas> glCanvas;
+
+void initGLview(Evas_Object *obj)
+{
+ static constexpr auto BPP = 4;
+
+ //Create a Canvas
+ glCanvas = tvg::GlCanvas::gen();
+ glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT);
+
+ /* Push the shape into the Canvas drawing list
+ When this shape is into the canvas list, the shape could update & prepare
+ internal data asynchronously for coming rendering.
+ Canvas keeps this shape node unless user call canvas->clear() */
+ tvgDrawCmds(glCanvas.get());
+}
+
+void drawGLview(Evas_Object *obj)
+{
+ auto gl = elm_glview_gl_api_get(obj);
+ gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ gl->glClear(GL_COLOR_BUFFER_BIT);
+
+ if (glCanvas->draw() == tvg::Result::Success) {
+ glCanvas->sync();
+ }
+}
+
+
+/************************************************************************/
+/* Main Code */
+/************************************************************************/
+
+int main(int argc, char **argv)
+{
+ tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw;
+
+ if (argc > 1) {
+ if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl;
+ }
+
+ //Initialize ThorVG Engine
+ if (tvgEngine == tvg::CanvasEngine::Sw) {
+ cout << "tvg engine: software" << endl;
+ } else {
+ cout << "tvg engine: opengl" << endl;
+ }
+
+ //Threads Count
+ auto threads = std::thread::hardware_concurrency();
+
+ //Initialize ThorVG Engine
+ if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) {
+
+ elm_init(argc, argv);
+
+ if (tvgEngine == tvg::CanvasEngine::Sw) {
+ createSwView();
+ } else {
+ createGlView();
+ }
+
+ elm_run();
+ elm_shutdown();
+
+ //Terminate ThorVG Engine
+ tvg::Initializer::term(tvg::CanvasEngine::Sw);
+
+ if (data) free(data);
+
+ } else {
+ cout << "engine is not supported" << endl;
+ }
+ return 0;
+}
}
//Opaque Gradient
} else {
- for (uint32_t y = 0; y < h; ++y) {
- fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, 0, w);
+ if (surface->compositor) {
+ auto method = surface->compositor->method;
+ uint32_t *shape = fill->ctable;
+ auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
+ auto sbuffer = shape + (region.min.y ) + region.min.x;
+ for (uint32_t y = 0; y < h; ++y) {
+ auto dst = &buffer[y * surface->stride];
+ auto cmp = &cbuffer[y * surface->stride];
+ auto src = &sbuffer[y];
+ if (method == CompositeMethod::AlphaMask) {
+ for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp) {
+ auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
+ *dst = tmp + ALPHA_BLEND(*dst, surface->blender.alpha(tmp));
+ }
+ }
+ if (method == CompositeMethod::InvAlphaMask) {
+ for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp) {
+ auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
+ *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
+ }
+ }
+ }
+ } else {
+ for (uint32_t y = 0; y < h; ++y) {
+ fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, 0, w);
+ }
}
}
return true;
}
//Opaque Gradient
} else {
- for (uint32_t i = 0; i < rle->size; ++i) {
- if (span->coverage == 255) {
- fillFetchLinear(fill, surface->buffer + span->y * surface->stride, span->y, span->x, span->x, span->len);
- } else {
+ if (surface->compositor) {
+ auto method = surface->compositor->method;
+ auto cbuffer = surface->compositor->image.data;
+ auto tbuffer = static_cast<uint32_t*>(alloca(sizeof(uint32_t) * surface->w));
+ auto sbuffer = fill->ctable;
+ for (uint32_t i = 0; i < rle->size; ++i) {
auto dst = &surface->buffer[span->y * surface->stride + span->x];
- fillFetchLinear(fill, buf, span->y, span->x, 0, span->len);
- auto ialpha = 255 - span->coverage;
- for (uint32_t i = 0; i < span->len; ++i) {
- dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
+ auto cmp = &cbuffer[span->y * surface->stride + span->x];
+ auto tmp = tbuffer;
+ auto src = &sbuffer[span->y];
+ if (method == CompositeMethod::AlphaMask) {
+ for (uint32_t x = 0; x < span->len; ++x) {
+ auto ialpha = surface->blender.alpha(*cmp);
+ *tmp = ALPHA_BLEND(*src, ialpha);
+ dst[x] = *tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(*tmp));
+ ++tmp;
+ ++cmp;
+ }
+ }
+ else if (method == CompositeMethod::InvAlphaMask) {
+ for (uint32_t x = 0; x < span->len; ++x) {
+ auto ialpha = 255 - surface->blender.alpha(*cmp);
+ *tmp = ALPHA_BLEND(*src, ialpha);
+ dst[x] = *tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(*tmp));
+ ++tmp;
+ ++cmp;
+ }
}
+ ++span;
+ }
+ } else {
+ for (uint32_t i = 0; i < rle->size; ++i) {
+ if (span->coverage == 255) {
+ fillFetchLinear(fill, surface->buffer + span->y * surface->stride, span->y, span->x, span->x, span->len);
+ } else {
+ fillFetchLinear(fill, buf, span->y, span->x, 0, span->len);
+ auto ialpha = 255 - span->coverage;
+ auto dst = &surface->buffer[span->y * surface->stride + span->x];
+ for (uint32_t i = 0; i < span->len; ++i) {
+ dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
+ }
+ }
+ ++span;
}
- ++span;
}
}
return true;