mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 21:53:41 +00:00

This implementation supports shape + stroke opacity composition. Currently, tvg shape provides individual alpha values for filling & stroking These alpha values are working individually, meaning that if stroking is half translucent, user can see that translucent stroking is crossed the shape outlines. Sometimes this result can be expected but user also expects the shape filling is invisible behind of translucent stroking. For this reason, Paint provides an additional api opacity() that applies opacity value to whole paint attributes. This is a little expensive job, please consider if you can possibly avoid that usage. See Opacity example. @Issues: 94
173 lines
4.9 KiB
C++
173 lines
4.9 KiB
C++
#include "Common.h"
|
|
|
|
/************************************************************************/
|
|
/* Drawing Commands */
|
|
/************************************************************************/
|
|
|
|
void tvgDrawCmds(tvg::Canvas* canvas)
|
|
{
|
|
if (!canvas) return;
|
|
|
|
//Prepare Circle
|
|
auto shape1 = tvg::Shape::gen();
|
|
shape1->appendCircle(400, 400, 250, 250);
|
|
shape1->fill(255, 255, 0, 255);
|
|
canvas->push(move(shape1));
|
|
|
|
//Create a Scene
|
|
auto scene = tvg::Scene::gen();
|
|
scene->opacity(127); //Apply opacity to scene (0 - 255)
|
|
scene->reserve(2);
|
|
|
|
//Star
|
|
auto shape2 = tvg::Shape::gen();
|
|
|
|
//Appends Paths
|
|
shape2->moveTo(199, 34);
|
|
shape2->lineTo(253, 143);
|
|
shape2->lineTo(374, 160);
|
|
shape2->lineTo(287, 244);
|
|
shape2->lineTo(307, 365);
|
|
shape2->lineTo(199, 309);
|
|
shape2->lineTo(97, 365);
|
|
shape2->lineTo(112, 245);
|
|
shape2->lineTo(26, 161);
|
|
shape2->lineTo(146, 143);
|
|
shape2->close();
|
|
shape2->fill(0, 0, 255, 255);
|
|
shape2->stroke(10);
|
|
shape2->stroke(255, 255, 255, 255);
|
|
shape2->opacity(127);
|
|
|
|
scene->push(move(shape2));
|
|
|
|
//Circle
|
|
auto shape3 = tvg::Shape::gen();
|
|
|
|
auto cx = 550.0f;
|
|
auto cy = 550.0f;
|
|
auto radius = 125.0f;
|
|
auto halfRadius = radius * 0.552284f;
|
|
|
|
//Append Paths
|
|
shape3->moveTo(cx, cy - radius);
|
|
shape3->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy);
|
|
shape3->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius);
|
|
shape3->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy);
|
|
shape3->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius);
|
|
shape3->fill(255, 0, 0, 255);
|
|
shape3->stroke(10);
|
|
shape3->stroke(0, 0, 255, 255);
|
|
shape3->opacity(200);
|
|
scene->push(move(shape3));
|
|
|
|
//Draw the Scene onto the Canvas
|
|
canvas->push(move(scene));
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* 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(tvgEngine);
|
|
|
|
} else {
|
|
cout << "engine is not supported" << endl;
|
|
}
|
|
return 0;
|
|
}
|