common composite: code refactoring

Splited out ClipPath routine from other pixel compositions'
since yet it's unlikely compatible...

Also revise internal engine interfaces to be simpler.

This is a step forward to enhance masking feature.
This commit is contained in:
Hermet Park 2020-12-25 19:47:01 +09:00 committed by GitHub
parent 9cb256f473
commit 4767f83b99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 251 additions and 237 deletions

View file

@ -279,6 +279,7 @@ public:
Result size(float w, float h) noexcept;
Result size(float* w, float* h) const noexcept;
const uint32_t* data() const noexcept;
static std::unique_ptr<Picture> gen() noexcept;

View file

@ -12,11 +12,12 @@ void tvgDrawCmds(tvg::Canvas* canvas)
if (!canvas) return;
//Mask Target 2
#if 0
auto scene = tvg::Scene::gen();
scene->opacity(127);
scene->scale(1.2);
scene->reserve(2);
#endif
//Star
auto shape = tvg::Shape::gen();
@ -33,17 +34,20 @@ void tvgDrawCmds(tvg::Canvas* canvas)
shape->lineTo(146, 143);
shape->close();
shape->fill(0, 0, 255, 255);
shape->stroke(10);
shape->stroke(255, 255, 255, 255);
shape->opacity(127);
// shape->stroke(10);
// shape->stroke(255, 255, 255, 255);
//shape->opacity(127);
scene->push(move(shape));
// scene->push(move(shape));
//Alpha Mask
auto mask2 = tvg::Shape::gen();
mask2->appendCircle(200, 200, 125, 125);
mask2->fill(255, 255, 255, 100);
auto mask = tvg::Shape::gen();
mask->appendCircle(200, 200, 125, 125);
mask->fill(255, 255, 255, 255);
shape->composite(move(mask), tvg::CompositeMethod::AlphaMask);
canvas->push(move(shape));
#if 0
scene->composite(move(mask2), tvg::CompositeMethod::AlphaMask);
if (canvas->push(move(scene)) != tvg::Result::Success) return;
@ -66,9 +70,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
picture->composite(move(mask), tvg::CompositeMethod::AlphaMask);
if (canvas->push(move(picture)) != tvg::Result::Success) return;
#endif
}

View file

@ -54,6 +54,7 @@ class GlGeometry;
struct GlShape
{
const Shape* shape = nullptr;
float viewWd;
float viewHt;
RenderUpdateFlag updateFlag;

View file

@ -73,7 +73,7 @@ bool GlRenderer::sync()
}
bool GlRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
bool GlRenderer::renderRegion(TVG_UNUSED RenderData data, TVG_UNUSED uint32_t* x, TVG_UNUSED uint32_t* y, TVG_UNUSED uint32_t* w, TVG_UNUSED uint32_t* h)
{
return true;
}
@ -102,31 +102,29 @@ bool GlRenderer::postRender()
}
void* GlRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
void* GlRenderer::addCompositor(TVG_UNUSED CompositeMethod method, TVG_UNUSED uint32_t x, TVG_UNUSED uint32_t y, TVG_UNUSED uint32_t w, TVG_UNUSED uint32_t h, TVG_UNUSED uint32_t opacity)
{
//TODO: Prepare frameBuffer & Setup render target for composition
return nullptr;
}
bool GlRenderer::endComposite(void* ctx, uint32_t opacity)
bool GlRenderer::delCompositor(TVG_UNUSED void* cmp)
{
//TODO: Composite Framebuffer to main surface
//TODO: delete the given compositor and restore the context
return false;
}
bool GlRenderer::render(const Picture& picture, void *data)
bool GlRenderer::renderImage(TVG_UNUSED void* data, TVG_UNUSED void* cmp)
{
//TODO Draw Bitmap Image
return true;
return false;
}
bool GlRenderer::render(const Shape& shape, void* data)
bool GlRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
{
GlShape* sdata = static_cast<GlShape*>(data);
auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
uint8_t r, g, b, a;
@ -139,17 +137,17 @@ bool GlRenderer::render(const Shape& shape, void* data)
{
if (flags & RenderUpdateFlag::Gradient)
{
const Fill* gradient = shape.fill();
const Fill* gradient = sdata->shape->fill();
drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
}
else if (flags & RenderUpdateFlag::Color)
{
shape.fillColor(&r, &g, &b, &a);
sdata->shape->fillColor(&r, &g, &b, &a);
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
}
if (flags & RenderUpdateFlag::Stroke)
{
shape.strokeColor(&r, &g, &b, &a);
sdata->shape->strokeColor(&r, &g, &b, &a);
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
}
}
@ -158,9 +156,9 @@ bool GlRenderer::render(const Shape& shape, void* data)
}
bool GlRenderer::dispose(void *data)
bool GlRenderer::dispose(RenderData data)
{
GlShape* sdata = static_cast<GlShape*>(data);
auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
delete sdata;
@ -168,20 +166,21 @@ bool GlRenderer::dispose(void *data)
}
void* GlRenderer::prepare(TVG_UNUSED const Picture& picture, TVG_UNUSED void* data, TVG_UNUSED uint32_t *buffer, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array<Composite>& compList, TVG_UNUSED RenderUpdateFlag flags)
RenderData GlRenderer::prepare(TVG_UNUSED const Picture& picture, TVG_UNUSED RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array<RenderData>& clips, TVG_UNUSED RenderUpdateFlag flags)
{
//TODO:
return nullptr;
}
void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
RenderData GlRenderer::prepare(const Shape& shape, RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare shape data
GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) {
sdata = new GlShape;
if (!sdata) return nullptr;
sdata->shape = &shape;
}
sdata->viewWd = static_cast<float>(surface.w);

View file

@ -30,16 +30,16 @@ class GlRenderer : public RenderMethod
public:
Surface surface = {nullptr, 0, 0, 0};
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
bool dispose(void *data) override;
void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
bool endComposite(void* ctx, uint32_t opacity) override;
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
bool dispose(RenderData data) override;
void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
bool delCompositor(void* cmp) override;
bool preRender() override;
bool render(const Shape& shape, void *data) override;
bool render(const Picture& picture, void *data) override;
bool renderShape(RenderData data, void* cmp) override;
bool renderImage(RenderData data, void* cmp) override;
bool postRender() override;
bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
bool sync() override;
bool clear() override;

View file

@ -33,9 +33,11 @@ static uint32_t rendererCnt = 0;
struct SwComposite
{
SwSurface surface;
SwSurface* recover;
SwComposite* recover;
SwImage image;
SwBBox bbox;
CompositeMethod method;
uint32_t opacity;
bool valid;
};
@ -45,7 +47,7 @@ struct SwTask : Task
Matrix* transform = nullptr;
SwSurface* surface = nullptr;
RenderUpdateFlag flags = RenderUpdateFlag::None;
Array<Composite> compList;
Array<RenderData> clips;
uint32_t opacity;
SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region
@ -102,7 +104,7 @@ struct SwShapeTask : SwTask
shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition. */
auto antiAlias = (strokeAlpha == 255 && strokeWidth > 2) ? false : true;
if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.count > 0 ? true : false)) goto end;
if (!shapeGenRle(&shape, sdata, clip, antiAlias, clips.count > 0 ? true : false)) goto end;
++addStroking;
}
}
@ -131,10 +133,9 @@ struct SwShapeTask : SwTask
}
}
//Composition
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape;
if ((*comp).method == CompositeMethod::ClipPath) {
//Clip Path
for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
//Clip shape rle
if (shape.rle) {
if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
@ -145,9 +146,6 @@ struct SwShapeTask : SwTask
if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
}
} else if ((*comp).method == CompositeMethod::AlphaMask) {
rleAlphaMask(shape.rle, compShape->rle);
}
}
end:
shapeDelOutline(&shape, tid);
@ -167,7 +165,6 @@ struct SwImageTask : SwTask
{
SwImage image;
const Picture* pdata = nullptr;
uint32_t* pixels = nullptr;
void run(unsigned tid) override
{
@ -181,23 +178,19 @@ struct SwImageTask : SwTask
imageReset(&image);
if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end;
//Composition?
if (compList.count > 0) {
//Clip Path?
if (clips.count > 0) {
if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end;
if (image.rle) {
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape;
if ((*comp).method == CompositeMethod::ClipPath) {
for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
if (compShape->rect) rleClipRect(image.rle, &compShape->bbox);
else if (compShape->rle) rleClipPath(image.rle, compShape->rle);
} else if ((*comp).method == CompositeMethod::AlphaMask) {
rleAlphaMask(image.rle, compShape->rle);
}
}
}
}
}
if (pixels) image.data = pixels;
image.data = const_cast<uint32_t*>(pdata->data());
end:
imageDelOutline(&image, tid);
}
@ -255,6 +248,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
if (!surface) {
surface = new SwSurface;
if (!surface) return false;
mainSurface = surface;
}
surface->buffer = buffer;
@ -278,17 +272,72 @@ bool SwRenderer::postRender()
tasks.clear();
//Free Composite Caches
for (auto comp = composites.data; comp < (composites.data + composites.count); ++comp) {
for (auto comp = compositors.data; comp < (compositors.data + compositors.count); ++comp) {
free((*comp)->image.data);
delete(*comp);
}
composites.reset();
compositors.reset();
return true;
}
bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
bool SwRenderer::renderImage(RenderData data, TVG_UNUSED void* cmp)
{
auto task = static_cast<SwImageTask*>(data);
task->done();
if (task->opacity == 0) return true;
return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
}
bool SwRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
{
auto task = static_cast<SwShapeTask*>(data);
task->done();
if (task->opacity == 0) return true;
uint32_t opacity;
void *cmp2 = nullptr;
//Do Composition
if (task->compStroking) {
uint32_t x, y, w, h;
task->bounds(&x, &y, &w, &h);
opacity = 255;
//CompositeMethod::None is used for a default alpha blending
cmp2 = addCompositor(CompositeMethod::None, x, y, w, h, opacity);
//No Composition
} else {
opacity = task->opacity;
}
//Main raster stage
uint8_t r, g, b, a;
if (auto fill = task->sdata->fill()) {
//FIXME: pass opacity to apply gradient fill?
rasterGradientShape(surface, &task->shape, fill->id());
} else{
task->sdata->fillColor(&r, &g, &b, &a);
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a);
}
task->sdata->strokeColor(&r, &g, &b, &a);
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
//Composition (Shape + Stroke) stage
if (task->compStroking) delCompositor(cmp2);
return true;
}
bool SwRenderer::renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
static_cast<SwTask*>(data)->bounds(x, y, w, h);
@ -296,22 +345,12 @@ bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w,
}
bool SwRenderer::render(TVG_UNUSED const Picture& picture, void *data)
{
auto task = static_cast<SwImageTask*>(data);
task->done();
return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
}
void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
void* SwRenderer::addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity)
{
SwComposite* comp = nullptr;
//Use cached data
for (auto p = composites.data; p < (composites.data + composites.count); ++p) {
for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) {
if ((*p)->valid) {
comp = *p;
break;
@ -328,17 +367,19 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
delete(comp);
return nullptr;
}
composites.push(comp);
compositors.push(comp);
}
comp->valid = false;
comp->method = method;
comp->opacity = opacity;
//Boundary Check
if (x + w > surface->w) w = (surface->w - x);
if (y + h > surface->h) h = (surface->h - y);
#ifdef THORVG_LOG_ENABLED
printf("SW_ENGINE: Using intermediate opacity composition [Region: %d %d %d %d]\n", x, y, w, h);
printf("SW_ENGINE: Using intermediate composition [Method: %d][Region: %d %d %d %d]\n", (int)method, x, y, w, h);
#endif
comp->bbox.min.x = x;
@ -365,75 +406,38 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
comp->surface.w = comp->image.w;
comp->surface.h = comp->image.h;
//Switch active compositor
comp->recover = compositor; //Backup current compositor
compositor = comp;
//Switch render target
comp->recover = surface;
surface = &comp->surface;
return comp;
}
bool SwRenderer::endComposite(void* p, uint32_t opacity)
bool SwRenderer::delCompositor(void* ctx)
{
if (!p) return false;
auto comp = static_cast<SwComposite*>(p);
//Recover render target
surface = comp->recover;
auto ret = rasterImage(surface, &comp->image, nullptr, comp->bbox, opacity);
if (!ctx) return false;
auto comp = static_cast<SwComposite*>(ctx);
comp->valid = true;
return ret;
}
//Recover Context
compositor = comp->recover;
surface = compositor ? &compositor->surface : mainSurface;
bool SwRenderer::render(TVG_UNUSED const Shape& shape, void *data)
{
auto task = static_cast<SwShapeTask*>(data);
task->done();
if (task->opacity == 0) return true;
uint32_t opacity;
void *ctx = nullptr;
//Do Composition
if (task->compStroking) {
uint32_t x, y, w, h;
task->bounds(&x, &y, &w, &h);
ctx = beginComposite(x, y, w, h);
opacity = 255;
//No Composition
} else {
opacity = task->opacity;
//Default is alpha blending
if (comp->method == CompositeMethod::None) {
return rasterImage(surface, &comp->image, nullptr, comp->bbox, comp->opacity);
}
//Main raster stage
uint8_t r, g, b, a;
if (auto fill = task->sdata->fill()) {
//FIXME: pass opacity to apply gradient fill?
rasterGradientShape(surface, &task->shape, fill->id());
} else{
task->sdata->fillColor(&r, &g, &b, &a);
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a);
}
task->sdata->strokeColor(&r, &g, &b, &a);
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
//Composition (Shape + Stroke) stage
if (task->compStroking) endComposite(ctx, task->opacity);
return true;
}
bool SwRenderer::dispose(void *data)
bool SwRenderer::dispose(RenderData data)
{
auto task = static_cast<SwTask*>(data);
if (!task) return true;
@ -447,14 +451,19 @@ bool SwRenderer::dispose(void *data)
}
void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
if (compList.count > 0) {
if (flags == RenderUpdateFlag::None) return task;
//Finish previous task if it has duplicated request.
task->done();
if (clips.count > 0) {
//Guarantee composition targets get ready.
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
static_cast<SwShapeTask*>((*comp).edata)->done();
for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
static_cast<SwShapeTask*>(*comp)->done();
}
task->compList = compList;
task->clips = clips;
}
if (transform) {
@ -471,50 +480,34 @@ void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, u
tasks.push(task);
TaskScheduler::request(task);
return task;
}
void* SwRenderer::prepare(const Picture& pdata, void* data, uint32_t *pixels, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
RenderData SwRenderer::prepare(const Picture& pdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare task
auto task = static_cast<SwImageTask*>(data);
if (!task) {
task = new SwImageTask;
if (!task) return nullptr;
}
if (flags == RenderUpdateFlag::None) return task;
//Finish previous task if it has duplicated request.
task->done();
task->pdata = &pdata;
task->pixels = pixels;
prepareCommon(task, transform, opacity, compList, flags);
return task;
}
return prepareCommon(task, transform, opacity, clips, flags);
}
void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare task
auto task = static_cast<SwShapeTask*>(data);
if (!task) {
task = new SwShapeTask;
if (!task) return nullptr;
}
if (flags == RenderUpdateFlag::None) return task;
//Finish previous task if it has duplicated request.
task->done();
task->sdata = &sdata;
prepareCommon(task, transform, opacity, compList, flags);
return task;
}
return prepareCommon(task, transform, opacity, clips, flags);
}

View file

@ -26,8 +26,6 @@
struct SwSurface;
struct SwTask;
struct SwShapeTask;
struct SwImage;
struct SwComposite;
namespace tvg
@ -36,17 +34,17 @@ namespace tvg
class SwRenderer : public RenderMethod
{
public:
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
bool endComposite(void* ctx, uint32_t opacity) override;
bool dispose(void *data) override;
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
bool delCompositor(void* cmp) override;
bool dispose(RenderData data) override;
bool preRender() override;
bool postRender() override;
bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool clear() override;
bool render(const Shape& shape, void *data) override;
bool render(const Picture& picture, void *data) override;
bool renderShape(RenderData data, void* cmp) override;
bool renderImage(RenderData data, void* cmp) override;
bool sync() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
@ -55,14 +53,16 @@ public:
static bool term();
private:
SwSurface* surface = nullptr;
Array<SwTask*> tasks;
Array<SwComposite*> composites;
SwSurface* surface = nullptr; //active surface
SwComposite* compositor = nullptr; //active compositor
SwSurface* mainSurface = nullptr; //main (default) surface
Array<SwTask*> tasks; //async task list
Array<SwComposite*> compositors; //compositor cache list
SwRenderer(){};
~SwRenderer();
void prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags);
RenderData prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags);
};
}

View file

@ -76,15 +76,15 @@ struct Canvas::Impl
{
if (!renderer) return Result::InsufficientCondition;
Array<Composite> compList;
Array<RenderData> clips;
//Update single paint node
if (paint) {
paint->pImpl->update(*renderer, nullptr, 255, compList, RenderUpdateFlag::None);
paint->pImpl->update(*renderer, nullptr, 255, clips, RenderUpdateFlag::None);
//Update all retained paint nodes
} else {
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
(*paint)->pImpl->update(*renderer, nullptr, 255, compList, RenderUpdateFlag::None);
(*paint)->pImpl->update(*renderer, nullptr, 255, clips, RenderUpdateFlag::None);
}
}
return Result::Success;

View file

@ -34,7 +34,7 @@ namespace tvg
virtual ~StrategyMethod() {}
virtual bool dispose(RenderMethod& renderer) = 0;
virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag) = 0; //Return engine data if it has.
virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag) = 0; //Return engine data if it has.
virtual bool render(RenderMethod& renderer) = 0;
virtual bool bounds(float* x, float* y, float* w, float* h) const = 0;
virtual bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const = 0;
@ -137,7 +137,7 @@ namespace tvg
return smethod->dispose(renderer);
}
void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<Composite>& compList, uint32_t pFlag)
void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, uint32_t pFlag)
{
if (flag & RenderUpdateFlag::Transform) {
if (!rTransform) return nullptr;
@ -149,9 +149,9 @@ namespace tvg
void *compdata = nullptr;
if (compTarget && (compMethod != CompositeMethod::None)) {
compdata = compTarget->pImpl->update(renderer, pTransform, opacity, compList, pFlag);
if (compdata) compList.push({compdata, compMethod});
if (compTarget) {
compdata = compTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag);
if (compMethod == CompositeMethod::ClipPath) clips.push(compdata);
}
void *edata = nullptr;
@ -161,20 +161,34 @@ namespace tvg
if (rTransform && pTransform) {
RenderTransform outTransform(pTransform, rTransform);
edata = smethod->update(renderer, &outTransform, opacity, compList, newFlag);
edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag);
} else {
auto outTransform = pTransform ? pTransform : rTransform;
edata = smethod->update(renderer, outTransform, opacity, compList, newFlag);
edata = smethod->update(renderer, outTransform, opacity, clips, newFlag);
}
if (compdata) compList.pop();
if (compdata) clips.pop();
return edata;
}
bool render(RenderMethod& renderer)
{
return smethod->render(renderer);
void* cmp = nullptr;
/* Note: only ClipPath is processed in update() step */
if (compTarget && compMethod != CompositeMethod::ClipPath) {
uint32_t x, y, w, h;
if (!compTarget->pImpl->bounds(renderer, &x, &y, &w, &h)) return false;
cmp = renderer.addCompositor(compMethod, x, y, w, h, 255);
compTarget->pImpl->render(renderer);
}
auto ret = smethod->render(renderer);
renderer.delCompositor(cmp);
return ret;
}
Paint* duplicate()
@ -198,6 +212,7 @@ namespace tvg
bool composite(Paint* target, CompositeMethod method)
{
if (!target && method != CompositeMethod::None) return false;
if (target && method == CompositeMethod::None) return false;
compTarget = target;
compMethod = method;
return true;
@ -228,9 +243,9 @@ namespace tvg
return inst->dispose(renderer);
}
void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flag) override
void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag) override
{
return inst->update(renderer, transform, opacity, compList, flag);
return inst->update(renderer, transform, opacity, clips, flag);
}
bool render(RenderMethod& renderer) override

View file

@ -89,3 +89,11 @@ Result Picture::size(float* w, float* h) const noexcept
return Result::Success;
}
const uint32_t* Picture::data() const noexcept
{
//Try it, If not loaded yet.
if (pImpl->loader) return pImpl->loader->pixels();
return pImpl->pixels;
}

View file

@ -36,7 +36,7 @@ struct Picture::Impl
Paint* paint = nullptr;
uint32_t *pixels = nullptr;
Picture *picture = nullptr;
void *edata = nullptr; //engine data
void *rdata = nullptr; //engine data
float w = 0, h = 0;
bool resizing = false;
@ -53,7 +53,7 @@ struct Picture::Impl
return true;
}
else if (pixels) {
return renderer.dispose(edata);
return renderer.dispose(rdata);
}
return false;
}
@ -103,28 +103,28 @@ struct Picture::Impl
}
}
if (!pixels) {
pixels = (uint32_t*)loader->pixels();
pixels = const_cast<uint32_t*>(loader->pixels());
if (pixels) return RenderUpdateFlag::Image;
}
}
return RenderUpdateFlag::None;
}
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag)
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
{
uint32_t flag = reload();
auto flag = reload();
if (pixels) edata = renderer.prepare(*picture, edata, pixels, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
if (pixels) rdata = renderer.prepare(*picture, rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
else if (paint) {
if (resizing) resize();
edata = paint->pImpl->update(renderer, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
rdata = paint->pImpl->update(renderer, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
}
return edata;
return rdata;
}
bool render(RenderMethod &renderer)
{
if (pixels) return renderer.render(*picture, edata);
if (pixels) return renderer.renderImage(rdata, nullptr);
else if (paint) return paint->pImpl->render(renderer);
return false;
}
@ -155,8 +155,8 @@ struct Picture::Impl
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
if (edata) return renderer.renderRegion(edata, x, y, w, h);
if (paint) paint->pImpl->bounds(renderer, x, y, w, h);
if (rdata) return renderer.renderRegion(rdata, x, y, w, h);
if (paint) return paint->pImpl->bounds(renderer, x, y, w, h);
return false;
}

View file

@ -37,10 +37,7 @@ struct Surface
uint32_t cs;
};
struct Composite {
void* edata;
CompositeMethod method;
};
using RenderData = void*;
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, All = 64};
@ -60,21 +57,20 @@ struct RenderTransform
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
};
class RenderMethod
{
public:
virtual ~RenderMethod() {}
virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0;
virtual void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0;
virtual void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
virtual bool endComposite(void* ctx, uint32_t opacity) = 0;
virtual bool dispose(void *data) = 0;
virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
virtual RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
virtual void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) = 0;
virtual bool delCompositor(void* cmp) = 0;
virtual bool dispose(RenderData data) = 0;
virtual bool preRender() = 0;
virtual bool render(const Shape& shape, void *data) = 0;
virtual bool render(const Picture& picture, void *data) = 0;
virtual bool renderShape(RenderData data, void* cmp) = 0;
virtual bool renderImage(RenderData data, void* cmp) = 0;
virtual bool postRender() = 0;
virtual bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
virtual bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
virtual bool clear() = 0;
virtual bool sync() = 0;
};

View file

@ -44,41 +44,40 @@ struct Scene::Impl
return true;
}
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flag)
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag)
{
this->opacity = opacity;
/* Overriding opacity value. If this scene is half-translucent,
It must do intermeidate composition with that opacity value. */
if (opacity < 255 && opacity > 0) opacity = 255;
if (opacity > 0) opacity = 255;
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
(*paint)->pImpl->update(renderer, transform, opacity, clips, static_cast<uint32_t>(flag));
}
/* FXIME: it requires to return list of children engine data
This is necessary for scene composition */
void* edata = nullptr;
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
edata = (*paint)->pImpl->update(renderer, transform, opacity, compList, static_cast<uint32_t>(flag));
}
return edata;
return nullptr;
}
bool render(RenderMethod& renderer)
{
void* ctx = nullptr;
void* cmp = nullptr;
//Half translucent. This requires intermediate composition.
if (opacity < 255 && opacity > 0) {
//Half translucent. This condition requires intermediate composition.
if (opacity < 255 && opacity > 0 && (paints.count > 1)) {
uint32_t x, y, w, h;
if (!bounds(renderer, &x, &y, &w, &h)) return false;
ctx = renderer.beginComposite(x, y, w, h);
//CompositeMethod::None is used for a default alpha blending
cmp = renderer.addCompositor(CompositeMethod::None, x, y, w, h, opacity);
}
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
if (!(*paint)->pImpl->render(renderer)) return false;
}
if (ctx) return renderer.endComposite(ctx, opacity);
if (cmp) renderer.delCompositor(cmp);
return true;
}

View file

@ -199,7 +199,7 @@ struct Shape::Impl
ShapeStroke *stroke = nullptr;
uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
FillRule rule = FillRule::Winding;
void *edata = nullptr; //engine data
RenderData rdata = nullptr; //engine data
Shape *shape = nullptr;
uint32_t flag = RenderUpdateFlag::None;
@ -215,24 +215,24 @@ struct Shape::Impl
bool dispose(RenderMethod& renderer)
{
return renderer.dispose(edata);
return renderer.dispose(rdata);
}
bool render(RenderMethod& renderer)
{
return renderer.render(*shape, edata);
return renderer.renderShape(rdata, nullptr);
}
void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag)
void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
{
this->edata = renderer.prepare(*shape, this->edata, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
flag = RenderUpdateFlag::None;
return this->edata;
return this->rdata;
}
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
return renderer.renderRegion(edata, x, y, w, h);
return renderer.renderRegion(rdata, x, y, w, h);
}
bool bounds(float* x, float* y, float* w, float* h)