mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
common sw_engine: revise the masking implementation.
We re-implement the masking feature with image composition method. This patch is working only for single shape but settle up coming extensions.
This commit is contained in:
parent
333ff3a12b
commit
736d6ee4ef
14 changed files with 292 additions and 159 deletions
|
@ -100,10 +100,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
|
|||
|
||||
//////////////////////////////////////////////
|
||||
auto picture = tvg::Picture::gen();
|
||||
char buf[PATH_MAX];
|
||||
sprintf(buf,"%s/cartman.svg", EXAMPLE_DIR);
|
||||
|
||||
if (picture->load(buf) != tvg::Result::Success) return;
|
||||
if (picture->load(EXAMPLE_DIR"/cartman.svg") != tvg::Result::Success) return;
|
||||
|
||||
picture->scale(3);
|
||||
picture->translate(200, 400);
|
||||
|
|
|
@ -11,16 +11,35 @@ 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
|
||||
//Solid Rectangle
|
||||
auto shape = tvg::Shape::gen();
|
||||
shape->appendRect(0, 0, 400, 400, 0, 0);
|
||||
shape->fill(0, 0, 255, 255);
|
||||
|
||||
//Mask
|
||||
auto mask = tvg::Shape::gen();
|
||||
mask->appendCircle(200, 200, 125, 125);
|
||||
mask->fill(255, 0, 0, 255);
|
||||
shape->composite(move(mask), tvg::CompositeMethod::AlphaMask);
|
||||
canvas->push(move(shape));
|
||||
|
||||
//SVG
|
||||
auto svg = tvg::Picture::gen();
|
||||
if (svg->load(EXAMPLE_DIR"/cartman.svg") != tvg::Result::Success) return;
|
||||
svg->scale(3);
|
||||
svg->translate(50, 400);
|
||||
|
||||
//Mask2
|
||||
auto mask2 = tvg::Shape::gen();
|
||||
mask2->appendCircle(150, 500, 75, 75);
|
||||
mask2->appendRect(150, 500, 200, 200, 30, 30);
|
||||
mask2->fill(255, 255, 255, 255);
|
||||
svg->composite(move(mask2), tvg::CompositeMethod::AlphaMask);
|
||||
canvas->push(move(svg));
|
||||
|
||||
//Star
|
||||
|
||||
#if 0
|
||||
//Appends Paths
|
||||
shape->moveTo(199, 34);
|
||||
shape->lineTo(253, 143);
|
||||
|
@ -33,20 +52,12 @@ void tvgDrawCmds(tvg::Canvas* canvas)
|
|||
shape->lineTo(26, 161);
|
||||
shape->lineTo(146, 143);
|
||||
shape->close();
|
||||
shape->fill(0, 0, 255, 255);
|
||||
// shape->stroke(10);
|
||||
// shape->stroke(255, 255, 255, 255);
|
||||
#endif
|
||||
|
||||
//shape->opacity(127);
|
||||
|
||||
// scene->push(move(shape));
|
||||
|
||||
//Alpha Mask
|
||||
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;
|
||||
|
|
|
@ -73,7 +73,7 @@ bool GlRenderer::sync()
|
|||
}
|
||||
|
||||
|
||||
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)
|
||||
bool GlRenderer::region(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,27 +102,34 @@ bool GlRenderer::postRender()
|
|||
}
|
||||
|
||||
|
||||
Compositor* GlRenderer::addCompositor(TVG_UNUSED uint32_t x, TVG_UNUSED uint32_t y, TVG_UNUSED uint32_t w, TVG_UNUSED uint32_t h)
|
||||
Compositor* GlRenderer::target(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 Compositor* cmp)
|
||||
bool GlRenderer::beginComposite(TVG_UNUSED Compositor* cmp, CompositeMethod method, uint32_t opacity)
|
||||
{
|
||||
//TODO: delete the given compositor and restore the context
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GlRenderer::renderImage(TVG_UNUSED void* data, TVG_UNUSED Compositor* cmp)
|
||||
bool GlRenderer::endComposite(TVG_UNUSED Compositor* cmp)
|
||||
{
|
||||
//TODO: delete the given compositor and restore the context
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GlRenderer::renderImage(TVG_UNUSED void* data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GlRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp)
|
||||
bool GlRenderer::renderShape(RenderData data)
|
||||
{
|
||||
auto sdata = static_cast<GlShape*>(data);
|
||||
if (!sdata) return false;
|
||||
|
|
|
@ -32,18 +32,21 @@ 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;
|
||||
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, Compositor* cmp) override;
|
||||
bool renderImage(RenderData data, Compositor* cmp) override;
|
||||
bool renderShape(RenderData data) override;
|
||||
bool renderImage(RenderData data) override;
|
||||
bool postRender() override;
|
||||
bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
|
||||
bool dispose(RenderData data) override;;
|
||||
bool region(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;
|
||||
|
||||
Compositor* target(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
|
||||
bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override;
|
||||
bool endComposite(Compositor* cmp) override;
|
||||
|
||||
static GlRenderer* gen();
|
||||
static int init(TVG_UNUSED uint32_t threads);
|
||||
static int term();
|
||||
|
|
|
@ -226,9 +226,21 @@ struct SwBlender
|
|||
uint32_t (*alpha)(uint32_t rgba);
|
||||
};
|
||||
|
||||
struct SwCompositor;
|
||||
|
||||
struct SwSurface : Surface
|
||||
{
|
||||
SwBlender blender;
|
||||
SwBlender blender; //mandatory
|
||||
SwCompositor* compositor = nullptr; //compositor (optional)
|
||||
};
|
||||
|
||||
struct SwCompositor : Compositor
|
||||
{
|
||||
SwSurface* recoverSfc; //Recover surface when composition is started
|
||||
SwCompositor* recoverCmp; //Recover compositor when composition is done
|
||||
SwImage image;
|
||||
SwBBox bbox;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
static inline SwCoord TO_SWCOORD(float val)
|
||||
|
|
|
@ -92,7 +92,14 @@ static SwBBox _clipRegion(Surface* surface, SwBBox& in)
|
|||
}
|
||||
|
||||
|
||||
static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
|
||||
static bool _translucent(SwSurface* surface, uint8_t a)
|
||||
{
|
||||
if (a < 255) return true;
|
||||
if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _translucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
|
||||
{
|
||||
auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
|
||||
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
||||
|
@ -109,6 +116,46 @@ static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uin
|
|||
}
|
||||
|
||||
|
||||
static bool _translucentRectAlphaMask(SwSurface* surface, const SwBBox& region, uint32_t color)
|
||||
{
|
||||
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);
|
||||
|
||||
#ifdef THORVG_LOG_ENABLED
|
||||
printf("SW_ENGINE: Rectangle Alpha Mask Composition\n");
|
||||
#endif
|
||||
|
||||
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
|
||||
auto tbuffer = static_cast<uint32_t*>(alloca(sizeof(uint32_t) * w)); //temp buffer for intermediate processing
|
||||
|
||||
for (uint32_t y = 0; y < h; ++y) {
|
||||
auto dst = &buffer[y * surface->stride];
|
||||
auto cmp = &cbuffer[y * surface->stride];
|
||||
auto tmp = tbuffer;
|
||||
//Composition
|
||||
for (uint32_t x = 0; x < w; ++x) {
|
||||
*tmp = ALPHA_BLEND(color, surface->blender.alpha(*cmp));
|
||||
dst[x] = *tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(*tmp));
|
||||
++tmp;
|
||||
++cmp;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
|
||||
{
|
||||
if (surface->compositor) {
|
||||
if (surface->compositor->method == CompositeMethod::AlphaMask) {
|
||||
return _translucentRectAlphaMask(surface, region, color);
|
||||
}
|
||||
}
|
||||
return _translucentRect(surface, region, color);
|
||||
}
|
||||
|
||||
|
||||
static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
|
||||
{
|
||||
auto buffer = surface->buffer + (region.min.y * surface->stride);
|
||||
|
@ -122,10 +169,8 @@ static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t
|
|||
}
|
||||
|
||||
|
||||
static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color)
|
||||
static bool _translucentRle(SwSurface* surface, SwRleData* rle, uint32_t color)
|
||||
{
|
||||
if (!rle) return false;
|
||||
|
||||
auto span = rle->spans;
|
||||
uint32_t src;
|
||||
|
||||
|
@ -134,8 +179,8 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c
|
|||
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
|
||||
else src = color;
|
||||
auto ialpha = 255 - surface->blender.alpha(src);
|
||||
for (uint32_t i = 0; i < span->len; ++i) {
|
||||
dst[i] = src + ALPHA_BLEND(dst[i], ialpha);
|
||||
for (uint32_t x = 0; x < span->len; ++x) {
|
||||
dst[x] = src + ALPHA_BLEND(dst[x], ialpha);
|
||||
}
|
||||
++span;
|
||||
}
|
||||
|
@ -143,6 +188,47 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c
|
|||
}
|
||||
|
||||
|
||||
static bool _translucentRleAlphaMask(SwSurface* surface, SwRleData* rle, uint32_t color)
|
||||
{
|
||||
#ifdef THORVG_LOG_ENABLED
|
||||
printf("SW_ENGINE: Rle Alpha Mask Composition\n");
|
||||
#endif
|
||||
auto span = rle->spans;
|
||||
uint32_t src;
|
||||
auto tbuffer = static_cast<uint32_t*>(alloca(sizeof(uint32_t) * surface->w)); //temp buffer for intermediate processing
|
||||
auto cbuffer = surface->compositor->image.data;
|
||||
|
||||
for (uint32_t i = 0; i < rle->size; ++i) {
|
||||
auto dst = &surface->buffer[span->y * surface->stride + span->x];
|
||||
auto cmp = &cbuffer[span->y * surface->stride + span->x];
|
||||
auto tmp = tbuffer;
|
||||
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
|
||||
else src = color;
|
||||
for (uint32_t x = 0; x < span->len; ++x) {
|
||||
*tmp = ALPHA_BLEND(src, surface->blender.alpha(*cmp));
|
||||
dst[x] = *tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(*tmp));
|
||||
++tmp;
|
||||
++cmp;
|
||||
}
|
||||
++span;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color)
|
||||
{
|
||||
if (!rle) return false;
|
||||
|
||||
if (surface->compositor) {
|
||||
if (surface->compositor->method == CompositeMethod::AlphaMask) {
|
||||
return _translucentRleAlphaMask(surface, rle, color);
|
||||
}
|
||||
}
|
||||
return _translucentRle(surface, rle, color);
|
||||
}
|
||||
|
||||
|
||||
static bool _rasterTranslucentImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform)
|
||||
{
|
||||
auto span = rle->spans;
|
||||
|
@ -456,17 +542,18 @@ bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g,
|
|||
b = ALPHA_MULTIPLY(b, a);
|
||||
|
||||
auto color = surface->blender.join(r, g, b, a);
|
||||
auto translucent = _translucent(surface, a);
|
||||
|
||||
//Fast Track
|
||||
if (shape->rect) {
|
||||
auto region = _clipRegion(surface, shape->bbox);
|
||||
if (a == 255) return _rasterSolidRect(surface, region, color);
|
||||
return _rasterTranslucentRect(surface, region, color);
|
||||
} else{
|
||||
if (a == 255) return _rasterSolidRle(surface, shape->rle, color);
|
||||
if (translucent) return _rasterTranslucentRect(surface, region, color);
|
||||
return _rasterSolidRect(surface, region, color);
|
||||
}
|
||||
if (translucent) {
|
||||
return _rasterTranslucentRle(surface, shape->rle, color);
|
||||
}
|
||||
return false;
|
||||
return _rasterSolidRle(surface, shape->rle, color);
|
||||
}
|
||||
|
||||
|
||||
|
@ -477,9 +564,10 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint
|
|||
b = ALPHA_MULTIPLY(b, a);
|
||||
|
||||
auto color = surface->blender.join(r, g, b, a);
|
||||
auto translucent = _translucent(surface, a);
|
||||
|
||||
if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, color);
|
||||
return _rasterTranslucentRle(surface, shape->strokeRle, color);
|
||||
if (translucent) return _rasterTranslucentRle(surface, shape->strokeRle, color);
|
||||
return _rasterSolidRle(surface, shape->strokeRle, color);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,15 +30,6 @@
|
|||
static bool initEngine = false;
|
||||
static uint32_t rendererCnt = 0;
|
||||
|
||||
struct SwCompositor : Compositor
|
||||
{
|
||||
SwSurface surface;
|
||||
SwCompositor* recover;
|
||||
SwImage image;
|
||||
SwBBox bbox;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
|
||||
struct SwTask : Task
|
||||
{
|
||||
|
@ -51,10 +42,14 @@ struct SwTask : Task
|
|||
|
||||
void bounds(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
|
||||
{
|
||||
if (x) *x = bbox.min.x;
|
||||
if (y) *y = bbox.min.y;
|
||||
if (w) *w = bbox.max.x - bbox.min.x;
|
||||
if (h) *h = bbox.max.y - bbox.min.y;
|
||||
//Range over?
|
||||
auto xx = bbox.min.x > 0 ? bbox.min.x : 0;
|
||||
auto yy = bbox.min.y > 0 ? bbox.min.y : 0;
|
||||
|
||||
if (x) *x = xx;
|
||||
if (y) *y = yy;
|
||||
if (w) *w = bbox.max.x - xx;
|
||||
if (h) *h = bbox.max.y - yy;
|
||||
}
|
||||
|
||||
virtual bool dispose() = 0;
|
||||
|
@ -247,7 +242,6 @@ 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;
|
||||
|
@ -272,7 +266,8 @@ bool SwRenderer::postRender()
|
|||
|
||||
//Free Composite Caches
|
||||
for (auto comp = compositors.data; comp < (compositors.data + compositors.count); ++comp) {
|
||||
free((*comp)->image.data);
|
||||
free((*comp)->compositor->image.data);
|
||||
delete((*comp)->compositor);
|
||||
delete(*comp);
|
||||
}
|
||||
compositors.reset();
|
||||
|
@ -281,7 +276,7 @@ bool SwRenderer::postRender()
|
|||
}
|
||||
|
||||
|
||||
bool SwRenderer::renderImage(RenderData data, TVG_UNUSED Compositor* cmp)
|
||||
bool SwRenderer::renderImage(RenderData data)
|
||||
{
|
||||
auto task = static_cast<SwImageTask*>(data);
|
||||
task->done();
|
||||
|
@ -292,7 +287,7 @@ bool SwRenderer::renderImage(RenderData data, TVG_UNUSED Compositor* cmp)
|
|||
}
|
||||
|
||||
|
||||
bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp)
|
||||
bool SwRenderer::renderShape(RenderData data)
|
||||
{
|
||||
auto task = static_cast<SwShapeTask*>(data);
|
||||
task->done();
|
||||
|
@ -300,18 +295,16 @@ bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp)
|
|||
if (task->opacity == 0) return true;
|
||||
|
||||
uint32_t opacity;
|
||||
Compositor* cmp2 = nullptr;
|
||||
Compositor* cmp = nullptr;
|
||||
|
||||
//Do Composition
|
||||
//Do Stroking Composition
|
||||
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(x, y, w, h);
|
||||
cmp2->method = CompositeMethod::None;
|
||||
cmp2->opacity = task->opacity;
|
||||
//No Composition
|
||||
cmp = target(x, y, w, h);
|
||||
beginComposite(cmp, CompositeMethod::None, task->opacity);
|
||||
//No Stroking Composition
|
||||
} else {
|
||||
opacity = task->opacity;
|
||||
}
|
||||
|
@ -331,13 +324,12 @@ bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp)
|
|||
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->cmpStroking) delCompositor(cmp2);
|
||||
if (task->cmpStroking) endComposite(cmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SwRenderer::renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
|
||||
bool SwRenderer::region(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
|
||||
{
|
||||
static_cast<SwTask*>(data)->bounds(x, y, w, h);
|
||||
|
||||
|
@ -345,13 +337,31 @@ bool SwRenderer::renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_
|
|||
}
|
||||
|
||||
|
||||
Compositor* SwRenderer::addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||
bool SwRenderer::beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity)
|
||||
{
|
||||
SwCompositor* cmp = nullptr;
|
||||
if (!cmp) return false;
|
||||
auto p = static_cast<SwCompositor*>(cmp);
|
||||
|
||||
p->method = method;
|
||||
p->opacity = opacity;
|
||||
|
||||
//Current Context?
|
||||
if (p->method != CompositeMethod::None) {
|
||||
surface = p->recoverSfc;
|
||||
surface->compositor = p;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Compositor* SwRenderer::target(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||
{
|
||||
SwSurface* cmp = nullptr;
|
||||
|
||||
//Use cached data
|
||||
for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) {
|
||||
if ((*p)->valid) {
|
||||
if ((*p)->compositor->valid) {
|
||||
cmp = *p;
|
||||
break;
|
||||
}
|
||||
|
@ -359,19 +369,21 @@ Compositor* SwRenderer::addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32
|
|||
|
||||
//New Composition
|
||||
if (!cmp) {
|
||||
cmp = new SwCompositor;
|
||||
if (!cmp) return nullptr;
|
||||
cmp = new SwSurface;
|
||||
if (!cmp) goto err;
|
||||
|
||||
//Inherits attributes from main surface
|
||||
*cmp = *surface;
|
||||
|
||||
cmp->compositor = new SwCompositor;
|
||||
if (!cmp->compositor) goto err;
|
||||
|
||||
//SwImage, Optimize Me: Surface size from MainSurface(WxH) to Parameter W x H
|
||||
cmp->image.data = (uint32_t*) malloc(sizeof(uint32_t) * surface->w * surface->h);
|
||||
if (!cmp->image.data) {
|
||||
delete(cmp);
|
||||
return nullptr;
|
||||
}
|
||||
cmp->compositor->image.data = (uint32_t*) malloc(sizeof(uint32_t) * surface->w * surface->h);
|
||||
if (!cmp->compositor->image.data) goto err;
|
||||
compositors.push(cmp);
|
||||
}
|
||||
|
||||
cmp->valid = false;
|
||||
|
||||
//Boundary Check
|
||||
if (x + w > surface->w) w = (surface->w - x);
|
||||
if (y + h > surface->h) h = (surface->h - y);
|
||||
|
@ -380,42 +392,44 @@ Compositor* SwRenderer::addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32
|
|||
printf("SW_ENGINE: Using intermediate composition [Region: %d %d %d %d]\n", x, y, w, h);
|
||||
#endif
|
||||
|
||||
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
|
||||
cmp->surface.blender = surface->blender;
|
||||
cmp->surface.stride = surface->w;
|
||||
cmp->surface.cs = surface->cs;
|
||||
cmp->compositor->recoverSfc = surface;
|
||||
cmp->compositor->recoverCmp = surface->compositor;
|
||||
cmp->compositor->valid = false;
|
||||
cmp->compositor->bbox.min.x = x;
|
||||
cmp->compositor->bbox.min.y = y;
|
||||
cmp->compositor->bbox.max.x = x + w;
|
||||
cmp->compositor->bbox.max.y = y + h;
|
||||
cmp->compositor->image.w = surface->w;
|
||||
cmp->compositor->image.h = surface->h;
|
||||
|
||||
//We know partial clear region
|
||||
cmp->surface.buffer = cmp->image.data + (cmp->surface.stride * y + x);
|
||||
cmp->surface.w = w;
|
||||
cmp->surface.h = h;
|
||||
cmp->buffer = cmp->compositor->image.data + (cmp->stride * y + x);
|
||||
cmp->w = w;
|
||||
cmp->h = h;
|
||||
|
||||
rasterClear(&cmp->surface);
|
||||
rasterClear(cmp);
|
||||
|
||||
//Recover context
|
||||
cmp->surface.buffer = cmp->image.data;
|
||||
cmp->surface.w = cmp->image.w;
|
||||
cmp->surface.h = cmp->image.h;
|
||||
|
||||
//Switch active compositor
|
||||
cmp->recover = compositor; //Backup current compositor
|
||||
compositor = cmp;
|
||||
cmp->buffer = cmp->compositor->image.data;
|
||||
cmp->w = cmp->compositor->image.w;
|
||||
cmp->h = cmp->compositor->image.h;
|
||||
|
||||
//Switch render target
|
||||
surface = &cmp->surface;
|
||||
surface = cmp;
|
||||
|
||||
return cmp;
|
||||
return cmp->compositor;
|
||||
|
||||
err:
|
||||
if (cmp) {
|
||||
if (cmp->compositor) delete(cmp->compositor);
|
||||
delete(cmp);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::delCompositor(Compositor* cmp)
|
||||
bool SwRenderer::endComposite(Compositor* cmp)
|
||||
{
|
||||
if (!cmp) return false;
|
||||
|
||||
|
@ -423,8 +437,8 @@ bool SwRenderer::delCompositor(Compositor* cmp)
|
|||
p->valid = true;
|
||||
|
||||
//Recover Context
|
||||
compositor = p->recover;
|
||||
surface = compositor ? &compositor->surface : mainSurface;
|
||||
surface = p->recoverSfc;
|
||||
surface->compositor = p->recoverCmp;
|
||||
|
||||
//Default is alpha blending
|
||||
if (p->method == CompositeMethod::None) {
|
||||
|
|
|
@ -36,28 +36,29 @@ 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;
|
||||
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 renderShape(RenderData data) override;
|
||||
bool renderImage(RenderData data) override;
|
||||
bool postRender() override;
|
||||
bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
|
||||
bool dispose(RenderData data) override;
|
||||
bool region(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
|
||||
|
||||
bool clear() 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);
|
||||
|
||||
Compositor* target(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
|
||||
bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override;
|
||||
bool endComposite(Compositor* cmp) override;
|
||||
|
||||
static SwRenderer* gen();
|
||||
static bool init(uint32_t threads);
|
||||
static bool term();
|
||||
|
||||
private:
|
||||
SwSurface* surface = nullptr; //active surface
|
||||
SwCompositor* compositor = nullptr; //active compositor
|
||||
SwSurface* mainSurface = nullptr; //main (default) surface
|
||||
Array<SwTask*> tasks; //async task list
|
||||
Array<SwCompositor*> compositors; //compositor cache list
|
||||
Array<SwSurface*> compositors; //render targets cache list
|
||||
|
||||
SwRenderer(){};
|
||||
~SwRenderer();
|
||||
|
|
|
@ -97,7 +97,7 @@ struct Canvas::Impl
|
|||
if (!renderer->preRender()) return Result::InsufficientCondition;
|
||||
|
||||
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
|
||||
if (!(*paint)->pImpl->render(*renderer)) return Result::InsufficientCondition;
|
||||
if (!(*paint)->pImpl->render(*renderer, 255)) return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
if (!renderer->postRender()) return Result::InsufficientCondition;
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace tvg
|
|||
|
||||
virtual bool dispose(RenderMethod& renderer) = 0;
|
||||
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 render(RenderMethod& renderer, uint32_t opacity) = 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;
|
||||
virtual Paint* duplicate() = 0;
|
||||
|
@ -150,7 +150,7 @@ namespace tvg
|
|||
void *cmpData = nullptr;
|
||||
|
||||
if (cmpTarget) {
|
||||
cmpData = cmpTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag);
|
||||
cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag);
|
||||
if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData);
|
||||
}
|
||||
|
||||
|
@ -172,23 +172,25 @@ namespace tvg
|
|||
return edata;
|
||||
}
|
||||
|
||||
bool render(RenderMethod& renderer)
|
||||
bool render(RenderMethod& renderer, uint32_t opacity)
|
||||
{
|
||||
Compositor* cmp = nullptr;
|
||||
|
||||
/* Note: only ClipPath is processed in update() step */
|
||||
/* Note: only ClipPath is processed in update() step.
|
||||
Create a composition image. */
|
||||
if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) {
|
||||
uint32_t x, y, w, h;
|
||||
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);
|
||||
cmp = renderer.target(x, y, w, h);
|
||||
renderer.beginComposite(cmp, CompositeMethod::None, 255);
|
||||
cmpTarget->pImpl->render(renderer, 255);
|
||||
}
|
||||
|
||||
auto ret = smethod->render(renderer);
|
||||
if (cmp) renderer.beginComposite(cmp, CompositeMethod::AlphaMask, cmpTarget->pImpl->opacity);
|
||||
|
||||
renderer.delCompositor(cmp);
|
||||
auto ret = smethod->render(renderer, ((opacity * this->opacity) / 255));
|
||||
|
||||
if (cmp) renderer.endComposite(cmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -250,9 +252,9 @@ namespace tvg
|
|||
return inst->update(renderer, transform, opacity, clips, flag);
|
||||
}
|
||||
|
||||
bool render(RenderMethod& renderer) override
|
||||
bool render(RenderMethod& renderer, uint32_t opacity) override
|
||||
{
|
||||
return inst->render(renderer);
|
||||
return inst->render(renderer, opacity);
|
||||
}
|
||||
|
||||
Paint* duplicate() override
|
||||
|
|
|
@ -122,10 +122,10 @@ struct Picture::Impl
|
|||
return rdata;
|
||||
}
|
||||
|
||||
bool render(RenderMethod &renderer)
|
||||
bool render(RenderMethod &renderer, uint32_t opacity)
|
||||
{
|
||||
if (pixels) return renderer.renderImage(rdata, nullptr);
|
||||
else if (paint) return paint->pImpl->render(renderer);
|
||||
if (pixels) return renderer.renderImage(rdata);
|
||||
else if (paint) return paint->pImpl->render(renderer, opacity);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ struct Picture::Impl
|
|||
|
||||
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
|
||||
{
|
||||
if (rdata) return renderer.renderRegion(rdata, x, y, w, h);
|
||||
if (rdata) return renderer.region(rdata, x, y, w, h);
|
||||
if (paint) return paint->pImpl->bounds(renderer, x, y, w, h);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -67,16 +67,19 @@ struct RenderMethod
|
|||
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 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, Compositor* cmp) = 0;
|
||||
virtual bool renderImage(RenderData data, Compositor* cmp) = 0;
|
||||
virtual bool renderShape(RenderData data) = 0;
|
||||
virtual bool renderImage(RenderData data) = 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 dispose(RenderData data) = 0;
|
||||
virtual bool region(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
|
||||
|
||||
virtual bool clear() = 0;
|
||||
virtual bool sync() = 0;
|
||||
|
||||
virtual Compositor* target(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
|
||||
virtual bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) = 0;
|
||||
virtual bool endComposite(Compositor* cmp) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
struct Scene::Impl
|
||||
{
|
||||
Array<Paint*> paints;
|
||||
uint32_t opacity;
|
||||
|
||||
bool dispose(RenderMethod& renderer)
|
||||
{
|
||||
|
@ -46,8 +45,6 @@ struct Scene::Impl
|
|||
|
||||
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 > 0) opacity = 255;
|
||||
|
@ -61,25 +58,23 @@ struct Scene::Impl
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool render(RenderMethod& renderer)
|
||||
bool render(RenderMethod& renderer, uint32_t opacity)
|
||||
{
|
||||
Compositor* cmp = nullptr;
|
||||
|
||||
//Half translucent. This condition requires intermediate composition.
|
||||
if (opacity < 255 && opacity > 0 && (paints.count > 1)) {
|
||||
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(x, y, w, h);
|
||||
cmp->method = CompositeMethod::None;
|
||||
cmp->opacity = opacity;
|
||||
cmp = renderer.target(x, y, w, h);
|
||||
renderer.beginComposite(cmp, CompositeMethod::None, opacity);
|
||||
}
|
||||
|
||||
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
|
||||
if (!(*paint)->pImpl->render(renderer)) return false;
|
||||
if (!(*paint)->pImpl->render(renderer, opacity)) return false;
|
||||
}
|
||||
|
||||
if (cmp) renderer.delCompositor(cmp);
|
||||
if (cmp) renderer.endComposite(cmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -218,9 +218,9 @@ struct Shape::Impl
|
|||
return renderer.dispose(rdata);
|
||||
}
|
||||
|
||||
bool render(RenderMethod& renderer)
|
||||
bool render(RenderMethod& renderer, TVG_UNUSED uint32_t opacity)
|
||||
{
|
||||
return renderer.renderShape(rdata, nullptr);
|
||||
return renderer.renderShape(rdata);
|
||||
}
|
||||
|
||||
void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
|
||||
|
@ -232,7 +232,7 @@ struct Shape::Impl
|
|||
|
||||
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
|
||||
{
|
||||
return renderer.renderRegion(rdata, x, y, w, h);
|
||||
return renderer.region(rdata, x, y, w, h);
|
||||
}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h)
|
||||
|
|
Loading…
Add table
Reference in a new issue