SwRender & tvgPaint: Implement ClipPath feature (#68)

common sw_engine: Implement ClipPath feature

Paint object can composite by using composite API.
ClipPath composite is clipping by path unit of paint.
The following cases are supported.

Shape->composite(Shape);
Scene->composite(Shape);
Picture->composite(Shape);

Add enum
  enum CompMethod { None = 0, ClipPath };

Add APIs
  Result composite(std::unique_ptr<Paint> comp, CompMethod method) const noexcept;

* Example: Added testClipPath
This commit is contained in:
JunsuChoi 2020-10-07 11:21:23 +09:00 committed by GitHub
parent 740c59debd
commit c70d1b1e45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 455 additions and 36 deletions

View file

@ -56,6 +56,7 @@ enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo };
enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt };
enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter };
enum class TVG_EXPORT FillSpread { Pad = 0, Reflect, Repeat };
enum class TVG_EXPORT CompMethod { None = 0, ClipPath };
enum class TVG_EXPORT CanvasEngine { Sw = (1 << 1), Gl = (1 << 2)};
@ -93,6 +94,8 @@ public:
Result bounds(float* x, float* y, float* w, float* h) const noexcept;
Paint* duplicate() const noexcept;
Result composite(std::unique_ptr<Paint> target, CompMethod method) const noexcept;
_TVG_DECLARE_ACCESSOR();
_TVG_DECLARE_PRIVATE(Paint);
};

View file

@ -26,6 +26,7 @@ source_file = [
'testSvg.cpp',
'testTransform.cpp',
'testUpdate.cpp',
'testClipPath.cpp',
]
foreach current_file : source_file

View file

@ -0,0 +1,217 @@
#include "testCommon.h"
/************************************************************************/
/* Drawing Commands */
/************************************************************************/
void tvgDrawStar(tvg::Shape* star)
{
star->moveTo(199, 34);
star->lineTo(253, 143);
star->lineTo(374, 160);
star->lineTo(287, 244);
star->lineTo(307, 365);
star->lineTo(199, 309);
star->lineTo(97, 365);
star->lineTo(112, 245);
star->lineTo(26, 161);
star->lineTo(146, 143);
star->close();
}
void tvgDrawCmds(tvg::Canvas* canvas)
{
if (!canvas) return;
//Background
auto shape = tvg::Shape::gen();
shape->appendRect(0, 0, WIDTH, HEIGHT, 0, 0);
shape->fill(255, 255, 255, 255);
if (canvas->push(move(shape)) != tvg::Result::Success) return;
//////////////////////////////////////////////
auto scene = tvg::Scene::gen();
scene->reserve(2);
auto star1 = tvg::Shape::gen();
tvgDrawStar(star1.get());
star1->fill(255, 255, 0, 255);
star1->stroke(255 ,0, 0, 128);
star1->stroke(10);
//Move Star1
star1->translate(-10, -10);
auto clipStar = tvg::Shape::gen();
clipStar->appendCircle(200, 230, 110, 110);
clipStar->fill(255, 255, 255, 255); // clip object must have alpha.
clipStar->translate(10, 10);
star1->composite(move(clipStar), tvg::CompMethod::ClipPath);
auto star2 = tvg::Shape::gen();
tvgDrawStar(star2.get());
star2->fill(0, 255, 255, 64);
star2->stroke(0 ,255, 0, 128);
star2->stroke(10);
//Move Star2
star2->translate(10, 40);
auto clip = tvg::Shape::gen();
clip->appendCircle(200, 230, 130, 130);
clip->fill(255, 255, 255, 255); // clip object must have alpha.
clip->translate(10, 10);
scene->push(move(star1));
scene->push(move(star2));
//Clipping scene to shape
scene->composite(move(clip), tvg::CompMethod::ClipPath);
canvas->push(move(scene));
//////////////////////////////////////////////
auto star3 = tvg::Shape::gen();
tvgDrawStar(star3.get());
star3->translate(400, 0);
star3->fill(255, 255, 0, 255); //r, g, b, a
star3->stroke(255 ,0, 0, 128);
star3->stroke(10);
auto clipRect = tvg::Shape::gen();
clipRect->appendRect(480, 110, 200, 200, 0, 0); //x, y, w, h, rx, ry
clipRect->fill(255, 255, 255, 255); // clip object must have alpha.
clipRect->translate(20, 20);
//Clipping scene to rect(shape)
star3->composite(move(clipRect), tvg::CompMethod::ClipPath);
canvas->push(move(star3));
//////////////////////////////////////////////
auto picture = tvg::Picture::gen();
char buf[PATH_MAX];
sprintf(buf,"%s/cartman.svg", EXAMPLE_DIR);
if (picture->load(buf) != tvg::Result::Success) return;
picture->scale(3);
picture->translate(200, 400);
auto clipPath = tvg::Shape::gen();
clipPath->appendCircle(350, 510, 110, 110); //x, y, w, h, rx, ry
clipPath->appendCircle(350, 650, 50, 50); //x, y, w, h, rx, ry
clipPath->fill(255, 255, 255, 255); // clip object must have alpha.
clipPath->translate(20, 20);
//Clipping picture to path
picture->composite(move(clipPath), tvg::CompMethod::ClipPath);
canvas->push(move(picture));
}
/************************************************************************/
/* Sw Engine Test Code */
/************************************************************************/
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;
}

View file

@ -140,7 +140,7 @@ bool GlRenderer::dispose(TVG_UNUSED const Shape& shape, void *data)
}
void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const RenderTransform* transform, RenderUpdateFlag flags)
void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const RenderTransform* transform, vector<Composite>& compList, RenderUpdateFlag flags)
{
//prepare shape data
GlShape* sdata = static_cast<GlShape*>(data);

View file

@ -30,7 +30,7 @@ class GlRenderer : public RenderMethod
public:
Surface surface = {nullptr, 0, 0, 0};
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, vector<Composite>& compList, RenderUpdateFlag flags) override;
bool dispose(const Shape& shape, void *data) override;
bool preRender() override;
bool render(const Shape& shape, void *data) override;

View file

@ -270,7 +270,7 @@ SwFixed mathMean(SwFixed angle1, SwFixed angle2);
void shapeReset(SwShape* shape);
bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform);
bool shapePrepare(SwShape* shape, const Shape* sdata, const SwSize& clip, const Matrix* transform);
bool shapeGenRle(SwShape* shape, const Shape* sdata, const SwSize& clip, bool antiAlias);
bool shapeGenRle(SwShape* shape, const Shape* sdata, const SwSize& clip, bool antiAlias, bool hasComposite);
void shapeDelOutline(SwShape* shape);
void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip);
@ -293,6 +293,9 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x,
SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias);
void rleFree(SwRleData* rle);
void rleClipPath(SwRleData *rle, const SwRleData *clip);
void rleClipRect(SwRleData *rle, const SwBBox* clip);
bool rasterCompositor(SwSurface* surface);
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);

View file

@ -36,6 +36,7 @@ struct SwTask : Task
Matrix* transform = nullptr;
SwSurface* surface = nullptr;
RenderUpdateFlag flags = RenderUpdateFlag::None;
vector<Composite> compList;
void run() override
{
@ -58,10 +59,11 @@ struct SwTask : Task
if (!shapePrepare(&shape, sdata, clip, transform)) return;
if (renderShape) {
auto antiAlias = (strokeAlpha > 0 && strokeWidth >= 2) ? false : true;
if (!shapeGenRle(&shape, sdata, clip, antiAlias)) return;
if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.size() > 0 ? true : false)) return;
}
}
}
//Fill
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) {
auto fill = sdata->fill();
@ -82,6 +84,20 @@ struct SwTask : Task
shapeDelStroke(&shape);
}
}
//Composite clip-path
for (auto comp : compList) {
SwShape *compShape = &static_cast<SwTask*>(comp.edata)->shape;
if (comp.method == CompMethod::ClipPath) {
//Clip to fill(path) rle
if (shape.rle && compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
else if (shape.rle && compShape->rle) rleClipPath(shape.rle, compShape->rle);
//Clip to stroke rle
if (shape.strokeRle && compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
else if (shape.strokeRle && compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
}
}
shapeDelOutline(&shape);
}
};
@ -184,7 +200,7 @@ bool SwRenderer::dispose(TVG_UNUSED const Shape& sdata, void *data)
}
void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags)
void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, vector<Composite>& compList, RenderUpdateFlag flags)
{
//prepare task
auto task = static_cast<SwTask*>(data);
@ -196,6 +212,10 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform*
if (flags == RenderUpdateFlag::None || task->valid()) return task;
task->sdata = &sdata;
if (compList.size() > 0) {
for (auto comp : compList) static_cast<SwTask*>(comp.edata)->get();
task->compList.assign(compList.begin(), compList.end());
}
if (transform) {
if (!task->transform) task->transform = static_cast<Matrix*>(malloc(sizeof(Matrix)));

View file

@ -34,7 +34,7 @@ namespace tvg
class SwRenderer : public RenderMethod
{
public:
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, vector<Composite>& compList, RenderUpdateFlag flags) override;
bool dispose(const Shape& shape, void *data) override;
bool preRender() override;
bool postRender() override;

View file

@ -613,6 +613,95 @@ static int _genRle(RleWorker& rw)
}
SwSpan* _intersectSpansRegion(const SwRleData *clip, const SwRleData *targetRle, SwSpan *outSpans, uint32_t spanCnt)
{
auto out = outSpans;
auto spans = targetRle->spans;
auto end = targetRle->spans + targetRle->size;
auto clipSpans = clip->spans;
auto clipEnd = clip->spans + clip->size;
while (spanCnt && spans < end ) {
if (clipSpans > clipEnd) {
spans = end;
break;
}
if (clipSpans->y > spans->y) {
++spans;
continue;
}
if (spans->y != clipSpans->y) {
++clipSpans;
continue;
}
auto sx1 = spans->x;
auto sx2 = sx1 + spans->len;
auto cx1 = clipSpans->x;
auto cx2 = cx1 + clipSpans->len;
if (cx1 < sx1 && cx2 < sx1) {
++clipSpans;
continue;
}
else if (sx1 < cx1 && sx2 < cx1) {
++spans;
continue;
}
auto x = sx1 > cx1 ? sx1 : cx1;
auto len = (sx2 < cx2 ? sx2 : cx2) - x;
if (len) {
auto spansCorverage = spans->coverage;
auto clipSpansCoverage = clipSpans->coverage;
out->x = sx1 > cx1 ? sx1 : cx1;
out->len = (sx2 < cx2 ? sx2 : cx2) - out->x;
out->y = spans->y;
out->coverage = (uint8_t)((spansCorverage * clipSpansCoverage) >> 8);
++out;
--spanCnt;
}
if (sx2 < cx2) ++spans;
else ++clipSpans;
}
return out;
}
SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSpan *outSpans, uint32_t spanCnt)
{
auto out = outSpans;
auto spans = targetRle->spans;
auto end = targetRle->spans + targetRle->size;
auto minx = static_cast<int16_t>(bbox->min.x);
auto miny = static_cast<int16_t>(bbox->min.y);
auto maxx = minx + static_cast<int16_t>(bbox->max.x - bbox->min.x) - 1;
auto maxy = miny + static_cast<int16_t>(bbox->max.y - bbox->min.y) - 1;
while (spanCnt && spans < end ) {
if (spans->y > maxy) {
spans = end;
break;
}
if (spans->y < miny || spans->x > maxx || spans->x + spans->len <= minx) {
++spans;
continue;
}
if (spans->x < minx) {
out->len = (spans->len - (minx - spans->x)) < (maxx - minx + 1) ? (spans->len - (minx - spans->x)) : (maxx - minx + 1);
out->x = minx;
}
else {
out->x = spans->x;
out->len = spans->len < (maxx - spans->x + 1) ? spans->len : (maxx - spans->x + 1);
}
if (out->len != 0) {
out->y = spans->y;
out->coverage = spans->coverage;
++out;
}
++spans;
--spanCnt;
}
return out;
}
/************************************************************************/
/* External Class Implementation */
@ -746,4 +835,48 @@ void rleFree(SwRleData* rle)
if (!rle) return;
if (rle->spans) free(rle->spans);
free(rle);
}
}
void updateRleSpans(SwRleData *rle, SwSpan* curSpans, uint32_t size)
{
if (!rle->spans || !curSpans || size == 0) return;
rle->size = size;
rle->spans = static_cast<SwSpan*>(realloc(rle->spans, rle->size * sizeof(SwSpan)));
if (!rle->spans) return;
for (int i = 0; i < (int)rle->size ; i++)
{
rle->spans[i].x = curSpans[i].x;
rle->spans[i].y = curSpans[i].y;
rle->spans[i].len = curSpans[i].len;
rle->spans[i].coverage = curSpans[i].coverage;
}
}
void rleClipPath(SwRleData *rle, const SwRleData *clip)
{
if (rle->size == 0 || clip->size == 0) return;
auto spanCnt = rle->size > clip->size ? rle->size : clip->size;
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (spanCnt)));
if (!spans) return;
auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt);
//Update Spans
updateRleSpans(rle, spans, spansEnd - spans);
if (spans) free(spans);
}
void rleClipRect(SwRleData *rle, const SwBBox* clip)
{
if (rle->size == 0) return;
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (rle->size)));
if (!spans) return;
auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size);
//Update Spans
updateRleSpans(rle, spans, spansEnd - spans);
if (spans) free(spans);
}

View file

@ -459,14 +459,14 @@ bool shapePrepare(SwShape* shape, const Shape* sdata, const SwSize& clip, const
}
bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, const SwSize& clip, bool antiAlias)
bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, const SwSize& clip, bool antiAlias, bool hasComposite)
{
//FIXME: Should we draw it?
//Case: Stroke Line
//if (shape.outline->opened) return true;
//Case A: Fast Track Rectangle Drawing
if ((shape->rect = _fastTrack(shape->outline))) return true;
if (!hasComposite && (shape->rect = _fastTrack(shape->outline))) return true;
//Case B: Normale Shape RLE Drawing
if ((shape->rle = rleRender(shape->outline, shape->bbox, clip, antiAlias))) return true;
@ -687,4 +687,4 @@ void shapeDelFill(SwShape* shape)
if (!shape->fill) return;
fillFree(shape->fill);
shape->fill = nullptr;
}
}

View file

@ -64,6 +64,7 @@ struct Canvas::Impl
paint->pImpl->dispose(*renderer);
delete(paint);
}
paints.clear();
return Result::Success;
@ -73,15 +74,17 @@ struct Canvas::Impl
{
if (!renderer) return Result::InsufficientCondition;
vector<Composite> compList;
//Update single paint node
if (paint) {
if (!paint->pImpl->update(*renderer, nullptr, RenderUpdateFlag::None)) {
if (!paint->pImpl->update(*renderer, nullptr, compList, nullptr, RenderUpdateFlag::None)) {
return Result::InsufficientCondition;
}
//Update retained all paint nodes
} else {
for(auto paint: paints) {
if (!paint->pImpl->update(*renderer, nullptr, RenderUpdateFlag::None)) {
for (auto paint: paints) {
if (!paint->pImpl->update(*renderer, nullptr, compList, nullptr, RenderUpdateFlag::None)) {
return Result::InsufficientCondition;
}
}
@ -105,4 +108,4 @@ struct Canvas::Impl
}
};
#endif /* _TVG_CANVAS_IMPL_H_ */
#endif /* _TVG_CANVAS_IMPL_H_ */

View file

@ -67,7 +67,6 @@ Result Paint::transform(const Matrix& m) noexcept
return Result::FailedAllocation;
}
Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept
{
if (pImpl->bounds(x, y, w, h)) return Result::Success;
@ -77,4 +76,11 @@ Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept
Paint* Paint::duplicate() const noexcept
{
return pImpl->duplicate();
}
}
Result Paint::composite(std::unique_ptr<Paint> target, CompMethod method) const noexcept
{
if (pImpl->composite(target.release(), method)) return Result::Success;
return Result::InsufficientCondition;
}

View file

@ -33,7 +33,7 @@ namespace tvg
virtual ~StrategyMethod(){}
virtual bool dispose(RenderMethod& renderer) = 0;
virtual bool update(RenderMethod& renderer, const RenderTransform* transform, RenderUpdateFlag pFlag) = 0;
virtual bool update(RenderMethod& renderer, const RenderTransform* transform, vector<Composite> compList, void** edata, RenderUpdateFlag pFlag) = 0;
virtual bool render(RenderMethod& renderer) = 0;
virtual bool bounds(float* x, float* y, float* w, float* h) const = 0;
virtual Paint* duplicate() = 0;
@ -45,6 +45,9 @@ namespace tvg
RenderTransform *rTransform = nullptr;
uint32_t flag = RenderUpdateFlag::None;
Paint* compTarget = nullptr;
CompMethod compMethod = CompMethod::None;
~Impl() {
if (smethod) delete(smethod);
if (rTransform) delete(rTransform);
@ -120,10 +123,11 @@ namespace tvg
bool dispose(RenderMethod& renderer)
{
if (this->compTarget) this->compTarget->pImpl->dispose(renderer);
return smethod->dispose(renderer);
}
bool update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t pFlag)
bool update(RenderMethod& renderer, const RenderTransform* pTransform, vector<Composite>& compList, void **edata, uint32_t pFlag)
{
if (flag & RenderUpdateFlag::Transform) {
if (!rTransform) return false;
@ -135,14 +139,30 @@ namespace tvg
auto newFlag = static_cast<RenderUpdateFlag>(pFlag | flag);
flag = RenderUpdateFlag::None;
bool updated = false;
void *compEngineData = nullptr; //composite target paint's engine data.
if (this->compTarget && compMethod == CompMethod::ClipPath) {
if (this->compTarget->pImpl->update(renderer, pTransform, compList, &compEngineData, static_cast<RenderUpdateFlag>(pFlag | flag))) {
Composite comp;
comp.edata = compEngineData;
comp.method = this->compMethod;
compList.push_back(comp);
}
}
if (rTransform && pTransform) {
RenderTransform outTransform(pTransform, rTransform);
return smethod->update(renderer, &outTransform, newFlag);
updated = smethod->update(renderer, &outTransform, compList, edata, newFlag);
} else {
auto outTransform = pTransform ? pTransform : rTransform;
return smethod->update(renderer, outTransform, newFlag);
updated = smethod->update(renderer, outTransform, compList, edata, newFlag);
}
if (compEngineData) {
compList.pop_back();
}
return updated;
}
bool render(RenderMethod& renderer)
@ -165,6 +185,14 @@ namespace tvg
return ret;
}
bool composite(Paint* target, CompMethod compMethod)
{
this->compTarget = target;
this->compMethod = compMethod;
if (this->compTarget) return true;
return false;
}
};
@ -186,9 +214,9 @@ namespace tvg
return inst->dispose(renderer);
}
bool update(RenderMethod& renderer, const RenderTransform* transform, RenderUpdateFlag flag) override
bool update(RenderMethod& renderer, const RenderTransform* transform, vector<Composite> compList, void** edata, RenderUpdateFlag flag) override
{
return inst->update(renderer, transform, flag);
return inst->update(renderer, transform, compList, edata, flag);
}
bool render(RenderMethod& renderer) override

View file

@ -57,13 +57,13 @@ struct Picture::Impl
}
bool update(RenderMethod &renderer, const RenderTransform* transform, RenderUpdateFlag flag)
bool update(RenderMethod &renderer, const RenderTransform* transform, vector<Composite>& compList, void** edata, RenderUpdateFlag flag)
{
reload();
if (!paint) return false;
return paint->pImpl->update(renderer, transform, flag);
return paint->pImpl->update(renderer, transform, compList, edata, flag);
}
bool render(RenderMethod &renderer)
@ -126,4 +126,4 @@ struct Picture::Impl
}
};
#endif //_TVG_PICTURE_IMPL_H_
#endif //_TVG_PICTURE_IMPL_H_

View file

@ -22,6 +22,7 @@
#ifndef _TVG_RENDER_H_
#define _TVG_RENDER_H_
#include <vector>
#include "tvgCommon.h"
namespace tvg
@ -36,6 +37,11 @@ struct Surface
uint32_t cs;
};
struct Composite {
void* edata;
CompMethod method;
};
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, All = 32};
struct RenderTransform
@ -59,7 +65,7 @@ class RenderMethod
{
public:
virtual ~RenderMethod() {}
virtual void* prepare(TVG_UNUSED const Shape& shape, TVG_UNUSED void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED RenderUpdateFlag flags) { return nullptr; }
virtual void* prepare(TVG_UNUSED const Shape& shape, TVG_UNUSED void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED vector<Composite>& compList, TVG_UNUSED RenderUpdateFlag flags) { return nullptr; }
virtual bool dispose(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return true; }
virtual bool preRender() { return true; }
virtual bool render(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return true; }
@ -70,4 +76,4 @@ public:
}
#endif //_TVG_RENDER_H_
#endif //_TVG_RENDER_H_

View file

@ -44,10 +44,10 @@ struct Scene::Impl
return true;
}
bool update(RenderMethod &renderer, const RenderTransform* transform, RenderUpdateFlag flag)
bool update(RenderMethod &renderer, const RenderTransform* transform, vector<Composite>& compList, void** edata, RenderUpdateFlag flag)
{
for(auto paint: paints) {
if (!paint->pImpl->update(renderer, transform, static_cast<uint32_t>(flag))) return false;
for (auto paint: paints) {
if (!paint->pImpl->update(renderer, transform, compList, edata, static_cast<uint32_t>(flag))) return false;
}
return true;
}
@ -106,4 +106,4 @@ struct Scene::Impl
}
};
#endif //_TVG_SCENE_IMPL_H_
#endif //_TVG_SCENE_IMPL_H_

View file

@ -221,13 +221,12 @@ struct Shape::Impl
return renderer.render(*shape, edata);
}
bool update(RenderMethod& renderer, const RenderTransform* transform, RenderUpdateFlag pFlag)
bool update(RenderMethod& renderer, const RenderTransform* transform, vector<Composite>& compList, void** edata, RenderUpdateFlag pFlag)
{
edata = renderer.prepare(*shape, edata, transform, static_cast<RenderUpdateFlag>(pFlag | flag));
this->edata = renderer.prepare(*shape, this->edata, transform, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
flag = RenderUpdateFlag::None;
if (edata) return true;
if (edata) *edata = this->edata;
if (this->edata) return true;
return false;
}