common sw_engine: code refactoring

Renamed internal interfaces.

We need both blender & compositor interfaces.

Renamed SwCompositor -> SwBlender which is for pixel joining methods.

Added (SwCompositor, Compositor) which is designed for compositing images.
This commit is contained in:
Hermet Park 2020-12-25 20:44:07 +09:00
parent c1e36bcb01
commit 7d9023ac5c
10 changed files with 137 additions and 131 deletions

View file

@ -102,27 +102,27 @@ bool GlRenderer::postRender()
}
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)
Compositor* GlRenderer::addCompositor(TVG_UNUSED uint32_t x, TVG_UNUSED uint32_t y, TVG_UNUSED uint32_t w, TVG_UNUSED uint32_t h)
{
//TODO: Prepare frameBuffer & Setup render target for composition
return nullptr;
}
bool GlRenderer::delCompositor(TVG_UNUSED void* cmp)
bool GlRenderer::delCompositor(TVG_UNUSED Compositor* cmp)
{
//TODO: delete the given compositor and restore the context
return false;
}
bool GlRenderer::renderImage(TVG_UNUSED void* data, TVG_UNUSED void* cmp)
bool GlRenderer::renderImage(TVG_UNUSED void* data, TVG_UNUSED Compositor* cmp)
{
return false;
}
bool GlRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
bool GlRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp)
{
auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false;

View file

@ -33,11 +33,11 @@ public:
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;
Compositor* addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
bool delCompositor(Compositor* cmp) override;
bool preRender() override;
bool renderShape(RenderData data, void* cmp) override;
bool renderImage(RenderData data, void* cmp) override;
bool renderShape(RenderData data, Compositor* cmp) override;
bool renderImage(RenderData data, Compositor* cmp) override;
bool postRender() 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);

View file

@ -220,7 +220,7 @@ struct SwImage
uint32_t w, h;
};
struct SwCompositor
struct SwBlender
{
uint32_t (*join)(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
uint32_t (*alpha)(uint32_t rgba);
@ -228,7 +228,7 @@ struct SwCompositor
struct SwSurface : Surface
{
SwCompositor comp;
SwBlender blender;
};
static inline SwCoord TO_SWCOORD(float val)

View file

@ -52,7 +52,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, SwSurface* surfac
auto g = ALPHA_MULTIPLY(pColors->g, pColors->a);
auto b = ALPHA_MULTIPLY(pColors->b, pColors->a);
auto rgba = surface->comp.join(r, g, b, pColors->a);
auto rgba = surface->blender.join(r, g, b, pColors->a);
auto inc = 1.0f / static_cast<float>(GRADIENT_STOP_SIZE);
auto pos = 1.5f * inc;
uint32_t i = 0;
@ -75,7 +75,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, SwSurface* surfac
auto g = ALPHA_MULTIPLY(next->g, next->a);
auto b = ALPHA_MULTIPLY(next->b, next->a);
auto rgba2 = surface->comp.join(r, g, b, next->a);
auto rgba2 = surface->blender.join(r, g, b, next->a);
while (pos < next->offset && i < GRADIENT_STOP_SIZE) {
auto t = (pos - curr->offset) * delta;

View file

@ -97,7 +97,7 @@ static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uin
auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto ialpha = 255 - surface->comp.alpha(color);
auto ialpha = 255 - surface->blender.alpha(color);
for (uint32_t y = 0; y < h; ++y) {
auto dst = &buffer[y * surface->stride];
@ -133,7 +133,7 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c
auto dst = &surface->buffer[span->y * surface->stride + span->x];
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color;
auto ialpha = 255 - surface->comp.alpha(src);
auto ialpha = 255 - surface->blender.alpha(src);
for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = src + ALPHA_BLEND(dst[i], ialpha);
}
@ -157,7 +157,7 @@ static bool _rasterTranslucentImageRle(SwSurface* surface, SwRleData* rle, uint3
if (rX >= w || rY >= h) continue;
auto alpha = ALPHA_MULTIPLY(span->coverage, opacity);
auto src = ALPHA_BLEND(img[rY * w + rX], alpha); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->comp.alpha(src));
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
}
++span;
}
@ -178,7 +178,7 @@ static bool _rasterImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, u
auto rY = static_cast<uint32_t>(roundf((span->x + x) * invTransform->e21 + ey2));
if (rX >= w || rY >= h) continue;
auto src = ALPHA_BLEND(img[rY * w + rX], span->coverage); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->comp.alpha(src));
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
}
++span;
}
@ -197,7 +197,7 @@ static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t
auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
if (rX >= w || rY >= h) continue;
auto src = ALPHA_BLEND(img[rX + (rY * w)], opacity); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->comp.alpha(src));
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
}
}
return true;
@ -210,7 +210,7 @@ static bool _rasterImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t
auto dst = &surface->buffer[y * surface->stride + region.min.x];
auto src = img + region.min.x + (y * w); //TODO: need to use image's stride
for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
*dst = *src + ALPHA_BLEND(*dst, 255 - surface->comp.alpha(*src));
*dst = *src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(*src));
}
}
return true;
@ -228,7 +228,7 @@ static bool _rasterImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t
auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
if (rX >= w || rY >= h) continue;
auto src = img[rX + (rY * w)]; //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->comp.alpha(src));
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
}
}
return true;
@ -276,7 +276,7 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region,
auto dst = &buffer[y * surface->stride];
fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, 0, w);
for (uint32_t x = 0; x < w; ++x) {
dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->comp.alpha(tmpBuf[x]));
dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x]));
}
}
//Opaque Gradient
@ -307,7 +307,7 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
auto dst = &buffer[y * surface->stride];
fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w);
for (uint32_t x = 0; x < w; ++x) {
dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->comp.alpha(tmpBuf[x]));
dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x]));
}
}
//Opaque Gradient
@ -337,12 +337,12 @@ static bool _rasterLinearGradientRle(SwSurface* surface, SwRleData* rle, const S
fillFetchLinear(fill, buf, span->y, span->x, 0, span->len);
if (span->coverage == 255) {
for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(buf[i]));
dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i]));
}
} else {
for (uint32_t i = 0; i < span->len; ++i) {
auto tmp = ALPHA_BLEND(buf[i], span->coverage);
dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(tmp));
dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp));
}
}
++span;
@ -383,12 +383,12 @@ static bool _rasterRadialGradientRle(SwSurface* surface, SwRleData* rle, const S
fillFetchRadial(fill, buf, span->y, span->x, span->len);
if (span->coverage == 255) {
for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(buf[i]));
dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i]));
}
} else {
for (uint32_t i = 0; i < span->len; ++i) {
auto tmp = ALPHA_BLEND(buf[i], span->coverage);
dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->comp.alpha(tmp));
dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp));
}
}
++span;
@ -420,11 +420,11 @@ static bool _rasterRadialGradientRle(SwSurface* surface, SwRleData* rle, const S
bool rasterCompositor(SwSurface* surface)
{
if (surface->cs == SwCanvas::ABGR8888) {
surface->comp.alpha = _colorAlpha;
surface->comp.join = _abgrJoin;
surface->blender.alpha = _colorAlpha;
surface->blender.join = _abgrJoin;
} else if (surface->cs == SwCanvas::ARGB8888) {
surface->comp.alpha = _colorAlpha;
surface->comp.join = _argbJoin;
surface->blender.alpha = _colorAlpha;
surface->blender.join = _argbJoin;
} else {
//What Color Space ???
return false;
@ -455,7 +455,7 @@ bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g,
g = ALPHA_MULTIPLY(g, a);
b = ALPHA_MULTIPLY(b, a);
auto color = surface->comp.join(r, g, b, a);
auto color = surface->blender.join(r, g, b, a);
//Fast Track
if (shape->rect) {
@ -476,7 +476,7 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint
g = ALPHA_MULTIPLY(g, a);
b = ALPHA_MULTIPLY(b, a);
auto color = surface->comp.join(r, g, b, a);
auto color = surface->blender.join(r, g, b, a);
if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, color);
return _rasterTranslucentRle(surface, shape->strokeRle, color);

View file

@ -30,14 +30,12 @@
static bool initEngine = false;
static uint32_t rendererCnt = 0;
struct SwComposite
struct SwCompositor : Compositor
{
SwSurface surface;
SwComposite* recover;
SwCompositor* recover;
SwImage image;
SwBBox bbox;
CompositeMethod method;
uint32_t opacity;
bool valid;
};
@ -67,7 +65,7 @@ struct SwShapeTask : SwTask
{
SwShape shape;
const Shape* sdata = nullptr;
bool compStroking;
bool cmpStroking;
void run(unsigned tid) override
{
@ -134,23 +132,23 @@ struct SwShapeTask : SwTask
}
//Clip Path
for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
auto clipper = &static_cast<SwShapeTask*>(*clip)->shape;
//Clip shape rle
if (shape.rle) {
if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
else if (compShape->rle) rleClipPath(shape.rle, compShape->rle);
if (clipper->rect) rleClipRect(shape.rle, &clipper->bbox);
else if (clipper->rle) rleClipPath(shape.rle, clipper->rle);
}
//Clip stroke rle
if (shape.strokeRle) {
if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
if (clipper->rect) rleClipRect(shape.strokeRle, &clipper->bbox);
else if (clipper->rle) rleClipPath(shape.strokeRle, clipper->rle);
}
}
end:
shapeDelOutline(&shape, tid);
if (addStroking == 2 && opacity < 255) compStroking = true;
else compStroking = false;
if (addStroking == 2 && opacity < 255) cmpStroking = true;
else cmpStroking = false;
}
bool dispose() override
@ -182,10 +180,10 @@ struct SwImageTask : SwTask
if (clips.count > 0) {
if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end;
if (image.rle) {
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);
for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
auto clipper = &static_cast<SwShapeTask*>(*clip)->shape;
if (clipper->rect) rleClipRect(image.rle, &clipper->bbox);
else if (clipper->rle) rleClipPath(image.rle, clipper->rle);
}
}
}
@ -282,7 +280,7 @@ bool SwRenderer::postRender()
}
bool SwRenderer::renderImage(RenderData data, TVG_UNUSED void* cmp)
bool SwRenderer::renderImage(RenderData data, TVG_UNUSED Compositor* cmp)
{
auto task = static_cast<SwImageTask*>(data);
task->done();
@ -293,7 +291,7 @@ bool SwRenderer::renderImage(RenderData data, TVG_UNUSED void* cmp)
}
bool SwRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp)
{
auto task = static_cast<SwShapeTask*>(data);
task->done();
@ -301,15 +299,17 @@ bool SwRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
if (task->opacity == 0) return true;
uint32_t opacity;
void *cmp2 = nullptr;
Compositor* cmp2 = nullptr;
//Do Composition
if (task->compStroking) {
if (task->cmpStroking) {
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);
cmp2 = addCompositor(x, y, w, h);
cmp2->method = CompositeMethod::None;
cmp2->opacity = opacity;
//No Composition
} else {
opacity = task->opacity;
@ -332,7 +332,7 @@ bool SwRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
//Composition (Shape + Stroke) stage
if (task->compStroking) delCompositor(cmp2);
if (task->cmpStroking) delCompositor(cmp2);
return true;
}
@ -345,92 +345,90 @@ bool SwRenderer::renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_
}
void* SwRenderer::addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity)
Compositor* SwRenderer::addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
SwComposite* comp = nullptr;
SwCompositor* cmp = nullptr;
//Use cached data
for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) {
if ((*p)->valid) {
comp = *p;
cmp = *p;
break;
}
}
//New Composition
if (!comp) {
comp = new SwComposite;
if (!comp) return nullptr;
if (!cmp) {
cmp = new SwCompositor;
if (!cmp) return nullptr;
//SwImage, Optimize Me: Surface size from MainSurface(WxH) to Parameter W x H
comp->image.data = (uint32_t*) malloc(sizeof(uint32_t) * surface->w * surface->h);
if (!comp->image.data) {
delete(comp);
cmp->image.data = (uint32_t*) malloc(sizeof(uint32_t) * surface->w * surface->h);
if (!cmp->image.data) {
delete(cmp);
return nullptr;
}
compositors.push(comp);
compositors.push(cmp);
}
comp->valid = false;
comp->method = method;
comp->opacity = opacity;
cmp->valid = false;
//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 composition [Method: %d][Region: %d %d %d %d]\n", (int)method, x, y, w, h);
printf("SW_ENGINE: Using intermediate composition [Region: %d %d %d %d]\n", x, y, w, h);
#endif
comp->bbox.min.x = x;
comp->bbox.min.y = y;
comp->bbox.max.x = x + w;
comp->bbox.max.y = y + h;
comp->image.w = surface->w;
comp->image.h = surface->h;
cmp->bbox.min.x = x;
cmp->bbox.min.y = y;
cmp->bbox.max.x = x + w;
cmp->bbox.max.y = y + h;
cmp->image.w = surface->w;
cmp->image.h = surface->h;
//Inherits attributes from main surface
comp->surface.comp = surface->comp;
comp->surface.stride = surface->w;
comp->surface.cs = surface->cs;
cmp->surface.blender = surface->blender;
cmp->surface.stride = surface->w;
cmp->surface.cs = surface->cs;
//We know partial clear region
comp->surface.buffer = comp->image.data + (comp->surface.stride * y + x);
comp->surface.w = w;
comp->surface.h = h;
cmp->surface.buffer = cmp->image.data + (cmp->surface.stride * y + x);
cmp->surface.w = w;
cmp->surface.h = h;
rasterClear(&comp->surface);
rasterClear(&cmp->surface);
//Recover context
comp->surface.buffer = comp->image.data;
comp->surface.w = comp->image.w;
comp->surface.h = comp->image.h;
cmp->surface.buffer = cmp->image.data;
cmp->surface.w = cmp->image.w;
cmp->surface.h = cmp->image.h;
//Switch active compositor
comp->recover = compositor; //Backup current compositor
compositor = comp;
cmp->recover = compositor; //Backup current compositor
compositor = cmp;
//Switch render target
surface = &comp->surface;
surface = &cmp->surface;
return comp;
return cmp;
}
bool SwRenderer::delCompositor(void* ctx)
bool SwRenderer::delCompositor(Compositor* cmp)
{
if (!ctx) return false;
if (!cmp) return false;
auto comp = static_cast<SwComposite*>(ctx);
comp->valid = true;
auto p = static_cast<SwCompositor*>(cmp);
p->valid = true;
//Recover Context
compositor = comp->recover;
compositor = p->recover;
surface = compositor ? &compositor->surface : mainSurface;
//Default is alpha blending
if (comp->method == CompositeMethod::None) {
return rasterImage(surface, &comp->image, nullptr, comp->bbox, comp->opacity);
if (p->method == CompositeMethod::None) {
return rasterImage(surface, &p->image, nullptr, p->bbox, p->opacity);
}
return true;
@ -460,8 +458,8 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
if (clips.count > 0) {
//Guarantee composition targets get ready.
for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
static_cast<SwShapeTask*>(*comp)->done();
for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
static_cast<SwShapeTask*>(*clip)->done();
}
task->clips = clips;
}

View file

@ -26,7 +26,7 @@
struct SwSurface;
struct SwTask;
struct SwComposite;
struct SwCompositor;
namespace tvg
{
@ -36,15 +36,15 @@ class SwRenderer : public RenderMethod
public:
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;
Compositor* addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
bool delCompositor(Compositor* cmp) override;
bool dispose(RenderData data) override;
bool preRender() override;
bool postRender() override;
bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool clear() override;
bool renderShape(RenderData data, void* cmp) override;
bool renderImage(RenderData data, void* cmp) override;
bool renderShape(RenderData data, Compositor* cmp) override;
bool renderImage(RenderData data, Compositor* cmp) override;
bool sync() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
@ -54,10 +54,10 @@ public:
private:
SwSurface* surface = nullptr; //active surface
SwComposite* compositor = nullptr; //active compositor
SwCompositor* compositor = nullptr; //active compositor
SwSurface* mainSurface = nullptr; //main (default) surface
Array<SwTask*> tasks; //async task list
Array<SwComposite*> compositors; //compositor cache list
Array<SwCompositor*> compositors; //compositor cache list
SwRenderer(){};
~SwRenderer();

View file

@ -47,13 +47,13 @@ namespace tvg
RenderTransform *rTransform = nullptr;
uint32_t flag = RenderUpdateFlag::None;
Paint* compTarget = nullptr;
CompositeMethod compMethod = CompositeMethod::None;
Paint* cmpTarget = nullptr;
CompositeMethod cmpMethod = CompositeMethod::None;
uint8_t opacity = 255;
~Impl() {
if (compTarget) delete(compTarget);
if (cmpTarget) delete(cmpTarget);
if (smethod) delete(smethod);
if (rTransform) delete(rTransform);
}
@ -133,7 +133,7 @@ namespace tvg
bool dispose(RenderMethod& renderer)
{
if (compTarget) compTarget->pImpl->dispose(renderer);
if (cmpTarget) cmpTarget->pImpl->dispose(renderer);
return smethod->dispose(renderer);
}
@ -147,11 +147,11 @@ namespace tvg
}
}
void *compdata = nullptr;
void *cmpData = nullptr;
if (compTarget) {
compdata = compTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag);
if (compMethod == CompositeMethod::ClipPath) clips.push(compdata);
if (cmpTarget) {
cmpData = cmpTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag);
if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData);
}
void *edata = nullptr;
@ -167,21 +167,23 @@ namespace tvg
edata = smethod->update(renderer, outTransform, opacity, clips, newFlag);
}
if (compdata) clips.pop();
if (cmpData) clips.pop();
return edata;
}
bool render(RenderMethod& renderer)
{
void* cmp = nullptr;
Compositor* cmp = nullptr;
/* Note: only ClipPath is processed in update() step */
if (compTarget && compMethod != CompositeMethod::ClipPath) {
if (cmpTarget && cmpMethod != 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);
if (!cmpTarget->pImpl->bounds(renderer, &x, &y, &w, &h)) return false;
cmp = renderer.addCompositor(x, y, w, h);
cmp->method = CompositeMethod::None;
cmp->opacity = 255;
cmpTarget->pImpl->render(renderer);
}
auto ret = smethod->render(renderer);
@ -213,8 +215,8 @@ namespace tvg
{
if (!target && method != CompositeMethod::None) return false;
if (target && method == CompositeMethod::None) return false;
compTarget = target;
compMethod = method;
cmpTarget = target;
cmpMethod = method;
return true;
}
};

View file

@ -39,6 +39,11 @@ struct Surface
using RenderData = void*;
struct Compositor {
CompositeMethod method;
uint32_t opacity;
};
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, All = 64};
struct RenderTransform
@ -57,18 +62,17 @@ struct RenderTransform
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
};
class RenderMethod
struct RenderMethod
{
public:
virtual ~RenderMethod() {}
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 Compositor* addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
virtual bool delCompositor(Compositor* cmp) = 0;
virtual bool dispose(RenderData data) = 0;
virtual bool preRender() = 0;
virtual bool renderShape(RenderData data, void* cmp) = 0;
virtual bool renderImage(RenderData data, void* cmp) = 0;
virtual bool renderShape(RenderData data, Compositor* cmp) = 0;
virtual bool renderImage(RenderData data, Compositor* cmp) = 0;
virtual bool postRender() = 0;
virtual bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
virtual bool clear() = 0;

View file

@ -63,14 +63,16 @@ struct Scene::Impl
bool render(RenderMethod& renderer)
{
void* cmp = nullptr;
Compositor* cmp = nullptr;
//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;
//CompositeMethod::None is used for a default alpha blending
cmp = renderer.addCompositor(CompositeMethod::None, x, y, w, h, opacity);
cmp = renderer.addCompositor(x, y, w, h);
cmp->method = CompositeMethod::None;
cmp->opacity = opacity;
}
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {