thorvg/src/examples/Opacity.cpp
Hermet Park af8c278c5e sw_engine raster: support opacity composition.
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
2020-12-03 13:07:17 +09:00

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;
}