mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
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:
parent
9cb256f473
commit
4767f83b99
14 changed files with 251 additions and 237 deletions
|
@ -279,6 +279,7 @@ public:
|
||||||
|
|
||||||
Result size(float w, float h) noexcept;
|
Result size(float w, float h) noexcept;
|
||||||
Result size(float* w, float* h) const noexcept;
|
Result size(float* w, float* h) const noexcept;
|
||||||
|
const uint32_t* data() const noexcept;
|
||||||
|
|
||||||
static std::unique_ptr<Picture> gen() noexcept;
|
static std::unique_ptr<Picture> gen() noexcept;
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,12 @@ void tvgDrawCmds(tvg::Canvas* canvas)
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
|
|
||||||
//Mask Target 2
|
//Mask Target 2
|
||||||
|
#if 0
|
||||||
auto scene = tvg::Scene::gen();
|
auto scene = tvg::Scene::gen();
|
||||||
scene->opacity(127);
|
scene->opacity(127);
|
||||||
scene->scale(1.2);
|
scene->scale(1.2);
|
||||||
scene->reserve(2);
|
scene->reserve(2);
|
||||||
|
#endif
|
||||||
//Star
|
//Star
|
||||||
auto shape = tvg::Shape::gen();
|
auto shape = tvg::Shape::gen();
|
||||||
|
|
||||||
|
@ -33,17 +34,20 @@ void tvgDrawCmds(tvg::Canvas* canvas)
|
||||||
shape->lineTo(146, 143);
|
shape->lineTo(146, 143);
|
||||||
shape->close();
|
shape->close();
|
||||||
shape->fill(0, 0, 255, 255);
|
shape->fill(0, 0, 255, 255);
|
||||||
shape->stroke(10);
|
// shape->stroke(10);
|
||||||
shape->stroke(255, 255, 255, 255);
|
// shape->stroke(255, 255, 255, 255);
|
||||||
shape->opacity(127);
|
//shape->opacity(127);
|
||||||
|
|
||||||
scene->push(move(shape));
|
// scene->push(move(shape));
|
||||||
|
|
||||||
//Alpha Mask
|
//Alpha Mask
|
||||||
auto mask2 = tvg::Shape::gen();
|
auto mask = tvg::Shape::gen();
|
||||||
mask2->appendCircle(200, 200, 125, 125);
|
mask->appendCircle(200, 200, 125, 125);
|
||||||
mask2->fill(255, 255, 255, 100);
|
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);
|
scene->composite(move(mask2), tvg::CompositeMethod::AlphaMask);
|
||||||
if (canvas->push(move(scene)) != tvg::Result::Success) return;
|
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);
|
picture->composite(move(mask), tvg::CompositeMethod::AlphaMask);
|
||||||
if (canvas->push(move(picture)) != tvg::Result::Success) return;
|
if (canvas->push(move(picture)) != tvg::Result::Success) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ class GlGeometry;
|
||||||
|
|
||||||
struct GlShape
|
struct GlShape
|
||||||
{
|
{
|
||||||
|
const Shape* shape = nullptr;
|
||||||
float viewWd;
|
float viewWd;
|
||||||
float viewHt;
|
float viewHt;
|
||||||
RenderUpdateFlag updateFlag;
|
RenderUpdateFlag updateFlag;
|
||||||
|
|
|
@ -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;
|
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
|
//TODO: Prepare frameBuffer & Setup render target for composition
|
||||||
return nullptr;
|
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;
|
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 false;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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;
|
if (!sdata) return false;
|
||||||
|
|
||||||
uint8_t r, g, b, a;
|
uint8_t r, g, b, a;
|
||||||
|
@ -139,17 +137,17 @@ bool GlRenderer::render(const Shape& shape, void* data)
|
||||||
{
|
{
|
||||||
if (flags & RenderUpdateFlag::Gradient)
|
if (flags & RenderUpdateFlag::Gradient)
|
||||||
{
|
{
|
||||||
const Fill* gradient = shape.fill();
|
const Fill* gradient = sdata->shape->fill();
|
||||||
drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
|
drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
|
||||||
}
|
}
|
||||||
else if (flags & RenderUpdateFlag::Color)
|
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);
|
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
|
||||||
}
|
}
|
||||||
if (flags & RenderUpdateFlag::Stroke)
|
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);
|
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;
|
if (!sdata) return false;
|
||||||
|
|
||||||
delete sdata;
|
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:
|
//TODO:
|
||||||
return nullptr;
|
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
|
//prepare shape data
|
||||||
GlShape* sdata = static_cast<GlShape*>(data);
|
GlShape* sdata = static_cast<GlShape*>(data);
|
||||||
if (!sdata) {
|
if (!sdata) {
|
||||||
sdata = new GlShape;
|
sdata = new GlShape;
|
||||||
if (!sdata) return nullptr;
|
if (!sdata) return nullptr;
|
||||||
|
sdata->shape = &shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdata->viewWd = static_cast<float>(surface.w);
|
sdata->viewWd = static_cast<float>(surface.w);
|
||||||
|
|
|
@ -30,16 +30,16 @@ class GlRenderer : public RenderMethod
|
||||||
public:
|
public:
|
||||||
Surface surface = {nullptr, 0, 0, 0};
|
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;
|
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, 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;
|
RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
||||||
bool dispose(void *data) override;
|
bool dispose(RenderData data) override;
|
||||||
void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
|
void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
|
||||||
bool endComposite(void* ctx, uint32_t opacity) override;
|
bool delCompositor(void* cmp) override;
|
||||||
bool preRender() override;
|
bool preRender() override;
|
||||||
bool render(const Shape& shape, void *data) override;
|
bool renderShape(RenderData data, void* cmp) override;
|
||||||
bool render(const Picture& picture, void *data) override;
|
bool renderImage(RenderData data, void* cmp) override;
|
||||||
bool postRender() 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 target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
|
||||||
bool sync() override;
|
bool sync() override;
|
||||||
bool clear() override;
|
bool clear() override;
|
||||||
|
|
|
@ -33,9 +33,11 @@ static uint32_t rendererCnt = 0;
|
||||||
struct SwComposite
|
struct SwComposite
|
||||||
{
|
{
|
||||||
SwSurface surface;
|
SwSurface surface;
|
||||||
SwSurface* recover;
|
SwComposite* recover;
|
||||||
SwImage image;
|
SwImage image;
|
||||||
SwBBox bbox;
|
SwBBox bbox;
|
||||||
|
CompositeMethod method;
|
||||||
|
uint32_t opacity;
|
||||||
bool valid;
|
bool valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ struct SwTask : Task
|
||||||
Matrix* transform = nullptr;
|
Matrix* transform = nullptr;
|
||||||
SwSurface* surface = nullptr;
|
SwSurface* surface = nullptr;
|
||||||
RenderUpdateFlag flags = RenderUpdateFlag::None;
|
RenderUpdateFlag flags = RenderUpdateFlag::None;
|
||||||
Array<Composite> compList;
|
Array<RenderData> clips;
|
||||||
uint32_t opacity;
|
uint32_t opacity;
|
||||||
SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region
|
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.
|
shape outline below stroke could be full covered by stroke drawing.
|
||||||
Thus it turns off antialising in that condition. */
|
Thus it turns off antialising in that condition. */
|
||||||
auto antiAlias = (strokeAlpha == 255 && strokeWidth > 2) ? false : true;
|
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;
|
++addStroking;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,22 +133,18 @@ struct SwShapeTask : SwTask
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Composition
|
//Clip Path
|
||||||
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
|
for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
|
||||||
auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape;
|
auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
|
||||||
if ((*comp).method == CompositeMethod::ClipPath) {
|
//Clip shape rle
|
||||||
//Clip shape rle
|
if (shape.rle) {
|
||||||
if (shape.rle) {
|
if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
|
||||||
if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
|
else if (compShape->rle) rleClipPath(shape.rle, compShape->rle);
|
||||||
else if (compShape->rle) rleClipPath(shape.rle, compShape->rle);
|
}
|
||||||
}
|
//Clip stroke rle
|
||||||
//Clip stroke rle
|
if (shape.strokeRle) {
|
||||||
if (shape.strokeRle) {
|
if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
|
||||||
if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
|
else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
|
||||||
else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
|
|
||||||
}
|
|
||||||
} else if ((*comp).method == CompositeMethod::AlphaMask) {
|
|
||||||
rleAlphaMask(shape.rle, compShape->rle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
|
@ -167,7 +165,6 @@ struct SwImageTask : SwTask
|
||||||
{
|
{
|
||||||
SwImage image;
|
SwImage image;
|
||||||
const Picture* pdata = nullptr;
|
const Picture* pdata = nullptr;
|
||||||
uint32_t* pixels = nullptr;
|
|
||||||
|
|
||||||
void run(unsigned tid) override
|
void run(unsigned tid) override
|
||||||
{
|
{
|
||||||
|
@ -181,23 +178,19 @@ struct SwImageTask : SwTask
|
||||||
imageReset(&image);
|
imageReset(&image);
|
||||||
if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end;
|
if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end;
|
||||||
|
|
||||||
//Composition?
|
//Clip Path?
|
||||||
if (compList.count > 0) {
|
if (clips.count > 0) {
|
||||||
if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end;
|
if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end;
|
||||||
if (image.rle) {
|
if (image.rle) {
|
||||||
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
|
for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
|
||||||
auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape;
|
auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
|
||||||
if ((*comp).method == CompositeMethod::ClipPath) {
|
if (compShape->rect) rleClipRect(image.rle, &compShape->bbox);
|
||||||
if (compShape->rect) rleClipRect(image.rle, &compShape->bbox);
|
else if (compShape->rle) rleClipPath(image.rle, compShape->rle);
|
||||||
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:
|
end:
|
||||||
imageDelOutline(&image, tid);
|
imageDelOutline(&image, tid);
|
||||||
}
|
}
|
||||||
|
@ -255,6 +248,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
surface = new SwSurface;
|
surface = new SwSurface;
|
||||||
if (!surface) return false;
|
if (!surface) return false;
|
||||||
|
mainSurface = surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
surface->buffer = buffer;
|
surface->buffer = buffer;
|
||||||
|
@ -278,17 +272,72 @@ bool SwRenderer::postRender()
|
||||||
tasks.clear();
|
tasks.clear();
|
||||||
|
|
||||||
//Free Composite Caches
|
//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);
|
free((*comp)->image.data);
|
||||||
delete(*comp);
|
delete(*comp);
|
||||||
}
|
}
|
||||||
composites.reset();
|
compositors.reset();
|
||||||
|
|
||||||
return true;
|
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);
|
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* SwRenderer::addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
SwComposite* comp = nullptr;
|
SwComposite* comp = nullptr;
|
||||||
|
|
||||||
//Use cached data
|
//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) {
|
if ((*p)->valid) {
|
||||||
comp = *p;
|
comp = *p;
|
||||||
break;
|
break;
|
||||||
|
@ -328,17 +367,19 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||||
delete(comp);
|
delete(comp);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
composites.push(comp);
|
compositors.push(comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
comp->valid = false;
|
comp->valid = false;
|
||||||
|
comp->method = method;
|
||||||
|
comp->opacity = opacity;
|
||||||
|
|
||||||
//Boundary Check
|
//Boundary Check
|
||||||
if (x + w > surface->w) w = (surface->w - x);
|
if (x + w > surface->w) w = (surface->w - x);
|
||||||
if (y + h > surface->h) h = (surface->h - y);
|
if (y + h > surface->h) h = (surface->h - y);
|
||||||
|
|
||||||
#ifdef THORVG_LOG_ENABLED
|
#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
|
#endif
|
||||||
|
|
||||||
comp->bbox.min.x = x;
|
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.w = comp->image.w;
|
||||||
comp->surface.h = comp->image.h;
|
comp->surface.h = comp->image.h;
|
||||||
|
|
||||||
|
//Switch active compositor
|
||||||
|
comp->recover = compositor; //Backup current compositor
|
||||||
|
compositor = comp;
|
||||||
|
|
||||||
//Switch render target
|
//Switch render target
|
||||||
comp->recover = surface;
|
|
||||||
surface = &comp->surface;
|
surface = &comp->surface;
|
||||||
|
|
||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SwRenderer::endComposite(void* p, uint32_t opacity)
|
bool SwRenderer::delCompositor(void* ctx)
|
||||||
{
|
{
|
||||||
if (!p) return false;
|
if (!ctx) return false;
|
||||||
auto comp = static_cast<SwComposite*>(p);
|
|
||||||
|
|
||||||
//Recover render target
|
|
||||||
surface = comp->recover;
|
|
||||||
|
|
||||||
auto ret = rasterImage(surface, &comp->image, nullptr, comp->bbox, opacity);
|
|
||||||
|
|
||||||
|
auto comp = static_cast<SwComposite*>(ctx);
|
||||||
comp->valid = true;
|
comp->valid = true;
|
||||||
|
|
||||||
return ret;
|
//Recover Context
|
||||||
}
|
compositor = comp->recover;
|
||||||
|
surface = compositor ? &compositor->surface : mainSurface;
|
||||||
|
|
||||||
|
//Default is alpha blending
|
||||||
bool SwRenderer::render(TVG_UNUSED const Shape& shape, void *data)
|
if (comp->method == CompositeMethod::None) {
|
||||||
{
|
return rasterImage(surface, &comp->image, nullptr, comp->bbox, comp->opacity);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SwRenderer::dispose(void *data)
|
bool SwRenderer::dispose(RenderData data)
|
||||||
{
|
{
|
||||||
auto task = static_cast<SwTask*>(data);
|
auto task = static_cast<SwTask*>(data);
|
||||||
if (!task) return true;
|
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.
|
//Guarantee composition targets get ready.
|
||||||
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
|
for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
|
||||||
static_cast<SwShapeTask*>((*comp).edata)->done();
|
static_cast<SwShapeTask*>(*comp)->done();
|
||||||
}
|
}
|
||||||
task->compList = compList;
|
task->clips = clips;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transform) {
|
if (transform) {
|
||||||
|
@ -471,50 +480,34 @@ void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, u
|
||||||
|
|
||||||
tasks.push(task);
|
tasks.push(task);
|
||||||
TaskScheduler::request(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
|
//prepare task
|
||||||
auto task = static_cast<SwImageTask*>(data);
|
auto task = static_cast<SwImageTask*>(data);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
task = new SwImageTask;
|
task = new SwImageTask;
|
||||||
if (!task) return nullptr;
|
if (!task) return nullptr;
|
||||||
|
task->pdata = &pdata;
|
||||||
}
|
}
|
||||||
|
return prepareCommon(task, transform, opacity, clips, flags);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
//prepare task
|
||||||
auto task = static_cast<SwShapeTask*>(data);
|
auto task = static_cast<SwShapeTask*>(data);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
task = new SwShapeTask;
|
task = new SwShapeTask;
|
||||||
if (!task) return nullptr;
|
if (!task) return nullptr;
|
||||||
|
task->sdata = &sdata;
|
||||||
}
|
}
|
||||||
|
return prepareCommon(task, transform, opacity, clips, flags);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,6 @@
|
||||||
|
|
||||||
struct SwSurface;
|
struct SwSurface;
|
||||||
struct SwTask;
|
struct SwTask;
|
||||||
struct SwShapeTask;
|
|
||||||
struct SwImage;
|
|
||||||
struct SwComposite;
|
struct SwComposite;
|
||||||
|
|
||||||
namespace tvg
|
namespace tvg
|
||||||
|
@ -36,17 +34,17 @@ namespace tvg
|
||||||
class SwRenderer : public RenderMethod
|
class SwRenderer : public RenderMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
|
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, 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;
|
RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
|
||||||
void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
|
void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
|
||||||
bool endComposite(void* ctx, uint32_t opacity) override;
|
bool delCompositor(void* cmp) override;
|
||||||
bool dispose(void *data) override;
|
bool dispose(RenderData data) override;
|
||||||
bool preRender() override;
|
bool preRender() override;
|
||||||
bool postRender() 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 clear() override;
|
||||||
bool render(const Shape& shape, void *data) override;
|
bool renderShape(RenderData data, void* cmp) override;
|
||||||
bool render(const Picture& picture, void *data) override;
|
bool renderImage(RenderData data, void* cmp) override;
|
||||||
bool sync() override;
|
bool sync() override;
|
||||||
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
|
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();
|
static bool term();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SwSurface* surface = nullptr;
|
SwSurface* surface = nullptr; //active surface
|
||||||
Array<SwTask*> tasks;
|
SwComposite* compositor = nullptr; //active compositor
|
||||||
Array<SwComposite*> composites;
|
SwSurface* mainSurface = nullptr; //main (default) surface
|
||||||
|
Array<SwTask*> tasks; //async task list
|
||||||
|
Array<SwComposite*> compositors; //compositor cache list
|
||||||
|
|
||||||
SwRenderer(){};
|
SwRenderer(){};
|
||||||
~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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,15 +76,15 @@ struct Canvas::Impl
|
||||||
{
|
{
|
||||||
if (!renderer) return Result::InsufficientCondition;
|
if (!renderer) return Result::InsufficientCondition;
|
||||||
|
|
||||||
Array<Composite> compList;
|
Array<RenderData> clips;
|
||||||
|
|
||||||
//Update single paint node
|
//Update single paint node
|
||||||
if (paint) {
|
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
|
//Update all retained paint nodes
|
||||||
} else {
|
} else {
|
||||||
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
|
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;
|
return Result::Success;
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace tvg
|
||||||
virtual ~StrategyMethod() {}
|
virtual ~StrategyMethod() {}
|
||||||
|
|
||||||
virtual bool dispose(RenderMethod& renderer) = 0;
|
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 render(RenderMethod& renderer) = 0;
|
||||||
virtual bool bounds(float* x, float* y, float* w, float* h) const = 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 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);
|
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 (flag & RenderUpdateFlag::Transform) {
|
||||||
if (!rTransform) return nullptr;
|
if (!rTransform) return nullptr;
|
||||||
|
@ -149,9 +149,9 @@ namespace tvg
|
||||||
|
|
||||||
void *compdata = nullptr;
|
void *compdata = nullptr;
|
||||||
|
|
||||||
if (compTarget && (compMethod != CompositeMethod::None)) {
|
if (compTarget) {
|
||||||
compdata = compTarget->pImpl->update(renderer, pTransform, opacity, compList, pFlag);
|
compdata = compTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag);
|
||||||
if (compdata) compList.push({compdata, compMethod});
|
if (compMethod == CompositeMethod::ClipPath) clips.push(compdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *edata = nullptr;
|
void *edata = nullptr;
|
||||||
|
@ -161,20 +161,34 @@ namespace tvg
|
||||||
|
|
||||||
if (rTransform && pTransform) {
|
if (rTransform && pTransform) {
|
||||||
RenderTransform outTransform(pTransform, rTransform);
|
RenderTransform outTransform(pTransform, rTransform);
|
||||||
edata = smethod->update(renderer, &outTransform, opacity, compList, newFlag);
|
edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag);
|
||||||
} else {
|
} else {
|
||||||
auto outTransform = pTransform ? pTransform : rTransform;
|
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;
|
return edata;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool render(RenderMethod& renderer)
|
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()
|
Paint* duplicate()
|
||||||
|
@ -198,6 +212,7 @@ namespace tvg
|
||||||
bool composite(Paint* target, CompositeMethod method)
|
bool composite(Paint* target, CompositeMethod method)
|
||||||
{
|
{
|
||||||
if (!target && method != CompositeMethod::None) return false;
|
if (!target && method != CompositeMethod::None) return false;
|
||||||
|
if (target && method == CompositeMethod::None) return false;
|
||||||
compTarget = target;
|
compTarget = target;
|
||||||
compMethod = method;
|
compMethod = method;
|
||||||
return true;
|
return true;
|
||||||
|
@ -228,9 +243,9 @@ namespace tvg
|
||||||
return inst->dispose(renderer);
|
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
|
bool render(RenderMethod& renderer) override
|
||||||
|
|
|
@ -89,3 +89,11 @@ Result Picture::size(float* w, float* h) const noexcept
|
||||||
return Result::Success;
|
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;
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ struct Picture::Impl
|
||||||
Paint* paint = nullptr;
|
Paint* paint = nullptr;
|
||||||
uint32_t *pixels = nullptr;
|
uint32_t *pixels = nullptr;
|
||||||
Picture *picture = nullptr;
|
Picture *picture = nullptr;
|
||||||
void *edata = nullptr; //engine data
|
void *rdata = nullptr; //engine data
|
||||||
float w = 0, h = 0;
|
float w = 0, h = 0;
|
||||||
bool resizing = false;
|
bool resizing = false;
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ struct Picture::Impl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (pixels) {
|
else if (pixels) {
|
||||||
return renderer.dispose(edata);
|
return renderer.dispose(rdata);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -103,28 +103,28 @@ struct Picture::Impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!pixels) {
|
if (!pixels) {
|
||||||
pixels = (uint32_t*)loader->pixels();
|
pixels = const_cast<uint32_t*>(loader->pixels());
|
||||||
if (pixels) return RenderUpdateFlag::Image;
|
if (pixels) return RenderUpdateFlag::Image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RenderUpdateFlag::None;
|
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) {
|
else if (paint) {
|
||||||
if (resizing) resize();
|
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)
|
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);
|
else if (paint) return paint->pImpl->render(renderer);
|
||||||
return false;
|
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)
|
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 (rdata) return renderer.renderRegion(rdata, x, y, w, h);
|
||||||
if (paint) paint->pImpl->bounds(renderer, x, y, w, h);
|
if (paint) return paint->pImpl->bounds(renderer, x, y, w, h);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,10 +37,7 @@ struct Surface
|
||||||
uint32_t cs;
|
uint32_t cs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Composite {
|
using RenderData = void*;
|
||||||
void* edata;
|
|
||||||
CompositeMethod method;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, All = 64};
|
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);
|
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class RenderMethod
|
class RenderMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~RenderMethod() {}
|
virtual ~RenderMethod() {}
|
||||||
virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0;
|
virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, 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 RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
|
||||||
virtual void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
|
virtual void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) = 0;
|
||||||
virtual bool endComposite(void* ctx, uint32_t opacity) = 0;
|
virtual bool delCompositor(void* cmp) = 0;
|
||||||
virtual bool dispose(void *data) = 0;
|
virtual bool dispose(RenderData data) = 0;
|
||||||
virtual bool preRender() = 0;
|
virtual bool preRender() = 0;
|
||||||
virtual bool render(const Shape& shape, void *data) = 0;
|
virtual bool renderShape(RenderData data, void* cmp) = 0;
|
||||||
virtual bool render(const Picture& picture, void *data) = 0;
|
virtual bool renderImage(RenderData data, void* cmp) = 0;
|
||||||
virtual bool postRender() = 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 clear() = 0;
|
||||||
virtual bool sync() = 0;
|
virtual bool sync() = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,41 +44,40 @@ struct Scene::Impl
|
||||||
return true;
|
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;
|
this->opacity = opacity;
|
||||||
|
|
||||||
/* Overriding opacity value. If this scene is half-translucent,
|
/* Overriding opacity value. If this scene is half-translucent,
|
||||||
It must do intermeidate composition with that opacity value. */
|
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
|
/* FXIME: it requires to return list of children engine data
|
||||||
This is necessary for scene composition */
|
This is necessary for scene composition */
|
||||||
void* edata = nullptr;
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool render(RenderMethod& renderer)
|
bool render(RenderMethod& renderer)
|
||||||
{
|
{
|
||||||
void* ctx = nullptr;
|
void* cmp = nullptr;
|
||||||
|
|
||||||
//Half translucent. This requires intermediate composition.
|
//Half translucent. This condition requires intermediate composition.
|
||||||
if (opacity < 255 && opacity > 0) {
|
if (opacity < 255 && opacity > 0 && (paints.count > 1)) {
|
||||||
uint32_t x, y, w, h;
|
uint32_t x, y, w, h;
|
||||||
if (!bounds(renderer, &x, &y, &w, &h)) return false;
|
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) {
|
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
|
||||||
if (!(*paint)->pImpl->render(renderer)) return false;
|
if (!(*paint)->pImpl->render(renderer)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx) return renderer.endComposite(ctx, opacity);
|
if (cmp) renderer.delCompositor(cmp);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,7 @@ struct Shape::Impl
|
||||||
ShapeStroke *stroke = nullptr;
|
ShapeStroke *stroke = nullptr;
|
||||||
uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
|
uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
|
||||||
FillRule rule = FillRule::Winding;
|
FillRule rule = FillRule::Winding;
|
||||||
void *edata = nullptr; //engine data
|
RenderData rdata = nullptr; //engine data
|
||||||
Shape *shape = nullptr;
|
Shape *shape = nullptr;
|
||||||
uint32_t flag = RenderUpdateFlag::None;
|
uint32_t flag = RenderUpdateFlag::None;
|
||||||
|
|
||||||
|
@ -215,24 +215,24 @@ struct Shape::Impl
|
||||||
|
|
||||||
bool dispose(RenderMethod& renderer)
|
bool dispose(RenderMethod& renderer)
|
||||||
{
|
{
|
||||||
return renderer.dispose(edata);
|
return renderer.dispose(rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool render(RenderMethod& renderer)
|
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;
|
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)
|
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)
|
bool bounds(float* x, float* y, float* w, float* h)
|
||||||
|
|
Loading…
Add table
Reference in a new issue