Result size(float w, float h) noexcept;
Result size(float* w, float* h) const noexcept;
+ const uint32_t* data() const noexcept;
static std::unique_ptr<Picture> gen() noexcept;
if (!canvas) return;
//Mask Target 2
+#if 0
auto scene = tvg::Scene::gen();
scene->opacity(127);
scene->scale(1.2);
scene->reserve(2);
-
+#endif
//Star
auto shape = tvg::Shape::gen();
shape->lineTo(146, 143);
shape->close();
shape->fill(0, 0, 255, 255);
- shape->stroke(10);
- shape->stroke(255, 255, 255, 255);
- shape->opacity(127);
+// shape->stroke(10);
+// shape->stroke(255, 255, 255, 255);
+ //shape->opacity(127);
- scene->push(move(shape));
+// scene->push(move(shape));
//Alpha Mask
- auto mask2 = tvg::Shape::gen();
- mask2->appendCircle(200, 200, 125, 125);
- mask2->fill(255, 255, 255, 100);
+ auto mask = tvg::Shape::gen();
+ mask->appendCircle(200, 200, 125, 125);
+ mask->fill(255, 255, 255, 255);
+ shape->composite(move(mask), tvg::CompositeMethod::AlphaMask);
+ canvas->push(move(shape));
+#if 0
scene->composite(move(mask2), tvg::CompositeMethod::AlphaMask);
if (canvas->push(move(scene)) != tvg::Result::Success) return;
picture->composite(move(mask), tvg::CompositeMethod::AlphaMask);
if (canvas->push(move(picture)) != tvg::Result::Success) return;
-
-
-
+#endif
}
\r
struct GlShape\r
{\r
+ const Shape* shape = nullptr;\r
float viewWd;\r
float viewHt;\r
RenderUpdateFlag updateFlag;\r
}
-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;
}
}
-void* GlRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+void* GlRenderer::addCompositor(TVG_UNUSED CompositeMethod method, TVG_UNUSED uint32_t x, TVG_UNUSED uint32_t y, TVG_UNUSED uint32_t w, TVG_UNUSED uint32_t h, TVG_UNUSED uint32_t opacity)
{
//TODO: Prepare frameBuffer & Setup render target for composition
return nullptr;
}
-bool GlRenderer::endComposite(void* ctx, uint32_t opacity)
+bool GlRenderer::delCompositor(TVG_UNUSED void* cmp)
{
- //TODO: Composite Framebuffer to main surface
+ //TODO: delete the given compositor and restore the context
return false;
}
-bool GlRenderer::render(const Picture& picture, void *data)
+bool GlRenderer::renderImage(TVG_UNUSED void* data, TVG_UNUSED void* cmp)
{
- //TODO Draw Bitmap Image
-
- return true;
+ return false;
}
-bool GlRenderer::render(const Shape& shape, void* data)
+bool GlRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
{
- GlShape* sdata = static_cast<GlShape*>(data);
+ auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
uint8_t r, g, b, a;
{
if (flags & RenderUpdateFlag::Gradient)
{
- const Fill* gradient = shape.fill();
+ const Fill* gradient = sdata->shape->fill();
drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
}
else if (flags & RenderUpdateFlag::Color)
{
- shape.fillColor(&r, &g, &b, &a);
+ sdata->shape->fillColor(&r, &g, &b, &a);
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
}
if (flags & RenderUpdateFlag::Stroke)
{
- shape.strokeColor(&r, &g, &b, &a);
+ sdata->shape->strokeColor(&r, &g, &b, &a);
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
}
}
}
-bool GlRenderer::dispose(void *data)
+bool GlRenderer::dispose(RenderData data)
{
- GlShape* sdata = static_cast<GlShape*>(data);
+ auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
delete sdata;
}
-void* GlRenderer::prepare(TVG_UNUSED const Picture& picture, TVG_UNUSED void* data, TVG_UNUSED uint32_t *buffer, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array<Composite>& compList, TVG_UNUSED RenderUpdateFlag flags)
+RenderData GlRenderer::prepare(TVG_UNUSED const Picture& picture, TVG_UNUSED RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array<RenderData>& clips, TVG_UNUSED RenderUpdateFlag flags)
{
//TODO:
return nullptr;
}
-void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
+RenderData GlRenderer::prepare(const Shape& shape, RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare shape data
GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) {
sdata = new GlShape;
if (!sdata) return nullptr;
+ sdata->shape = &shape;
}
sdata->viewWd = static_cast<float>(surface.w);
public:
Surface surface = {nullptr, 0, 0, 0};
- void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
- void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
- bool dispose(void *data) override;
- void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
- bool endComposite(void* ctx, uint32_t opacity) override;
+ RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+ RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+ bool dispose(RenderData data) override;
+ void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
+ bool delCompositor(void* cmp) override;
bool preRender() override;
- bool render(const Shape& shape, void *data) override;
- bool render(const Picture& picture, void *data) override;
+ bool renderShape(RenderData data, void* cmp) override;
+ bool renderImage(RenderData data, void* cmp) override;
bool postRender() override;
- bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
+ bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
bool sync() override;
bool clear() override;
struct SwComposite
{
SwSurface surface;
- SwSurface* recover;
+ SwComposite* recover;
SwImage image;
SwBBox bbox;
+ CompositeMethod method;
+ uint32_t opacity;
bool valid;
};
Matrix* transform = nullptr;
SwSurface* surface = nullptr;
RenderUpdateFlag flags = RenderUpdateFlag::None;
- Array<Composite> compList;
+ Array<RenderData> clips;
uint32_t opacity;
SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region
shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition. */
auto antiAlias = (strokeAlpha == 255 && strokeWidth > 2) ? false : true;
- if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.count > 0 ? true : false)) goto end;
+ if (!shapeGenRle(&shape, sdata, clip, antiAlias, clips.count > 0 ? true : false)) goto end;
++addStroking;
}
}
}
}
- //Composition
- for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
- auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape;
- if ((*comp).method == CompositeMethod::ClipPath) {
- //Clip shape rle
- if (shape.rle) {
- if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
- else if (compShape->rle) rleClipPath(shape.rle, compShape->rle);
- }
- //Clip stroke rle
- if (shape.strokeRle) {
- if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
- else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
- }
- } else if ((*comp).method == CompositeMethod::AlphaMask) {
- rleAlphaMask(shape.rle, compShape->rle);
+ //Clip Path
+ for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
+ auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
+ //Clip shape rle
+ if (shape.rle) {
+ if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
+ else if (compShape->rle) rleClipPath(shape.rle, compShape->rle);
+ }
+ //Clip stroke rle
+ if (shape.strokeRle) {
+ if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
+ else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
}
}
end:
{
SwImage image;
const Picture* pdata = nullptr;
- uint32_t* pixels = nullptr;
void run(unsigned tid) override
{
imageReset(&image);
if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end;
- //Composition?
- if (compList.count > 0) {
+ //Clip Path?
+ if (clips.count > 0) {
if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end;
if (image.rle) {
- for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
- auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape;
- if ((*comp).method == CompositeMethod::ClipPath) {
- if (compShape->rect) rleClipRect(image.rle, &compShape->bbox);
- else if (compShape->rle) rleClipPath(image.rle, compShape->rle);
- } else if ((*comp).method == CompositeMethod::AlphaMask) {
- rleAlphaMask(image.rle, compShape->rle);
- }
+ 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);
}
}
}
}
- if (pixels) image.data = pixels;
+ image.data = const_cast<uint32_t*>(pdata->data());
end:
imageDelOutline(&image, tid);
}
if (!surface) {
surface = new SwSurface;
if (!surface) return false;
+ mainSurface = surface;
}
surface->buffer = buffer;
tasks.clear();
//Free Composite Caches
- for (auto comp = composites.data; comp < (composites.data + composites.count); ++comp) {
+ for (auto comp = compositors.data; comp < (compositors.data + compositors.count); ++comp) {
free((*comp)->image.data);
delete(*comp);
}
- composites.reset();
+ compositors.reset();
return true;
}
-bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+bool SwRenderer::renderImage(RenderData data, TVG_UNUSED void* cmp)
{
- static_cast<SwTask*>(data)->bounds(x, y, w, h);
+ auto task = static_cast<SwImageTask*>(data);
+ task->done();
- return true;
-}
+ if (task->opacity == 0) return true;
+ return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
+}
-bool SwRenderer::render(TVG_UNUSED const Picture& picture, void *data)
+bool SwRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
{
- auto task = static_cast<SwImageTask*>(data);
+ auto task = static_cast<SwShapeTask*>(data);
task->done();
- return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
+ 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);
+
+ return true;
}
-void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+void* SwRenderer::addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity)
{
SwComposite* comp = nullptr;
//Use cached data
- for (auto p = composites.data; p < (composites.data + composites.count); ++p) {
+ for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) {
if ((*p)->valid) {
comp = *p;
break;
delete(comp);
return nullptr;
}
- composites.push(comp);
+ compositors.push(comp);
}
comp->valid = false;
+ comp->method = method;
+ comp->opacity = opacity;
//Boundary Check
if (x + w > surface->w) w = (surface->w - x);
if (y + h > surface->h) h = (surface->h - y);
#ifdef THORVG_LOG_ENABLED
- printf("SW_ENGINE: Using intermediate opacity composition [Region: %d %d %d %d]\n", x, y, w, h);
+ printf("SW_ENGINE: Using intermediate composition [Method: %d][Region: %d %d %d %d]\n", (int)method, x, y, w, h);
#endif
comp->bbox.min.x = x;
comp->surface.w = comp->image.w;
comp->surface.h = comp->image.h;
+ //Switch active compositor
+ comp->recover = compositor; //Backup current compositor
+ compositor = comp;
+
//Switch render target
- comp->recover = surface;
surface = &comp->surface;
return comp;
}
-bool SwRenderer::endComposite(void* p, uint32_t opacity)
+bool SwRenderer::delCompositor(void* ctx)
{
- if (!p) return false;
- auto comp = static_cast<SwComposite*>(p);
-
- //Recover render target
- surface = comp->recover;
-
- auto ret = rasterImage(surface, &comp->image, nullptr, comp->bbox, opacity);
+ if (!ctx) return false;
+ auto comp = static_cast<SwComposite*>(ctx);
comp->valid = true;
- return ret;
-}
-
+ //Recover Context
+ compositor = comp->recover;
+ surface = compositor ? &compositor->surface : mainSurface;
-bool SwRenderer::render(TVG_UNUSED const Shape& shape, void *data)
-{
- auto task = static_cast<SwShapeTask*>(data);
- task->done();
-
- if (task->opacity == 0) return true;
-
- uint32_t opacity;
- void *ctx = nullptr;
-
- //Do Composition
- if (task->compStroking) {
- uint32_t x, y, w, h;
- task->bounds(&x, &y, &w, &h);
- ctx = beginComposite(x, y, w, h);
- opacity = 255;
- //No Composition
- } else {
- opacity = task->opacity;
+ //Default is alpha blending
+ if (comp->method == CompositeMethod::None) {
+ return rasterImage(surface, &comp->image, nullptr, comp->bbox, comp->opacity);
}
- //Main raster stage
- uint8_t r, g, b, a;
-
- if (auto fill = task->sdata->fill()) {
- //FIXME: pass opacity to apply gradient fill?
- rasterGradientShape(surface, &task->shape, fill->id());
- } else{
- task->sdata->fillColor(&r, &g, &b, &a);
- a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
- if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a);
- }
-
- task->sdata->strokeColor(&r, &g, &b, &a);
- a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
- if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
-
- //Composition (Shape + Stroke) stage
- if (task->compStroking) endComposite(ctx, task->opacity);
-
return true;
}
-bool SwRenderer::dispose(void *data)
+bool SwRenderer::dispose(RenderData data)
{
auto task = static_cast<SwTask*>(data);
if (!task) return true;
}
-void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
+void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
- if (compList.count > 0) {
+ if (flags == RenderUpdateFlag::None) return task;
+
+ //Finish previous task if it has duplicated request.
+ task->done();
+
+ if (clips.count > 0) {
//Guarantee composition targets get ready.
- for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
- static_cast<SwShapeTask*>((*comp).edata)->done();
+ for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
+ static_cast<SwShapeTask*>(*comp)->done();
}
- task->compList = compList;
+ task->clips = clips;
}
if (transform) {
tasks.push(task);
TaskScheduler::request(task);
+
+ return task;
}
-void* SwRenderer::prepare(const Picture& pdata, void* data, uint32_t *pixels, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
+RenderData SwRenderer::prepare(const Picture& pdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare task
auto task = static_cast<SwImageTask*>(data);
if (!task) {
task = new SwImageTask;
if (!task) return nullptr;
+ task->pdata = &pdata;
}
-
- if (flags == RenderUpdateFlag::None) return task;
-
- //Finish previous task if it has duplicated request.
- task->done();
-
- task->pdata = &pdata;
- task->pixels = pixels;
-
- prepareCommon(task, transform, opacity, compList, flags);
-
- return task;
+ return prepareCommon(task, transform, opacity, clips, flags);
}
-void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
+RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare task
auto task = static_cast<SwShapeTask*>(data);
if (!task) {
task = new SwShapeTask;
if (!task) return nullptr;
+ task->sdata = &sdata;
}
-
- if (flags == RenderUpdateFlag::None) return task;
-
- //Finish previous task if it has duplicated request.
- task->done();
- task->sdata = &sdata;
-
- prepareCommon(task, transform, opacity, compList, flags);
-
- return task;
+ return prepareCommon(task, transform, opacity, clips, flags);
}
struct SwSurface;
struct SwTask;
-struct SwShapeTask;
-struct SwImage;
struct SwComposite;
namespace tvg
class SwRenderer : public RenderMethod
{
public:
- void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
- void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
- void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
- bool endComposite(void* ctx, uint32_t opacity) override;
- bool dispose(void *data) override;
+ RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+ RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+ void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
+ bool delCompositor(void* cmp) override;
+ bool dispose(RenderData data) override;
bool preRender() override;
bool postRender() override;
- bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
+ bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool clear() override;
- bool render(const Shape& shape, void *data) override;
- bool render(const Picture& picture, void *data) override;
+ bool renderShape(RenderData data, void* cmp) override;
+ bool renderImage(RenderData data, void* cmp) override;
bool sync() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
static bool term();
private:
- SwSurface* surface = nullptr;
- Array<SwTask*> tasks;
- Array<SwComposite*> composites;
+ SwSurface* surface = nullptr; //active surface
+ SwComposite* compositor = nullptr; //active compositor
+ SwSurface* mainSurface = nullptr; //main (default) surface
+ Array<SwTask*> tasks; //async task list
+ Array<SwComposite*> compositors; //compositor cache list
SwRenderer(){};
~SwRenderer();
- void prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags);
+ RenderData prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags);
};
}
{
if (!renderer) return Result::InsufficientCondition;
- Array<Composite> compList;
+ Array<RenderData> clips;
//Update single paint node
if (paint) {
- paint->pImpl->update(*renderer, nullptr, 255, compList, RenderUpdateFlag::None);
+ paint->pImpl->update(*renderer, nullptr, 255, clips, RenderUpdateFlag::None);
//Update all retained paint nodes
} else {
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
- (*paint)->pImpl->update(*renderer, nullptr, 255, compList, RenderUpdateFlag::None);
+ (*paint)->pImpl->update(*renderer, nullptr, 255, clips, RenderUpdateFlag::None);
}
}
return Result::Success;
virtual ~StrategyMethod() {}
virtual bool dispose(RenderMethod& renderer) = 0;
- virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag) = 0; //Return engine data if it has.
+ virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag) = 0; //Return engine data if it has.
virtual bool render(RenderMethod& renderer) = 0;
virtual bool bounds(float* x, float* y, float* w, float* h) const = 0;
virtual bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const = 0;
return smethod->dispose(renderer);
}
- void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<Composite>& compList, uint32_t pFlag)
+ void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, uint32_t pFlag)
{
if (flag & RenderUpdateFlag::Transform) {
if (!rTransform) return nullptr;
void *compdata = nullptr;
- if (compTarget && (compMethod != CompositeMethod::None)) {
- compdata = compTarget->pImpl->update(renderer, pTransform, opacity, compList, pFlag);
- if (compdata) compList.push({compdata, compMethod});
+ if (compTarget) {
+ compdata = compTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag);
+ if (compMethod == CompositeMethod::ClipPath) clips.push(compdata);
}
void *edata = nullptr;
if (rTransform && pTransform) {
RenderTransform outTransform(pTransform, rTransform);
- edata = smethod->update(renderer, &outTransform, opacity, compList, newFlag);
+ edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag);
} else {
auto outTransform = pTransform ? pTransform : rTransform;
- edata = smethod->update(renderer, outTransform, opacity, compList, newFlag);
+ edata = smethod->update(renderer, outTransform, opacity, clips, newFlag);
}
- if (compdata) compList.pop();
+ if (compdata) clips.pop();
return edata;
}
bool render(RenderMethod& renderer)
{
- return smethod->render(renderer);
+ void* cmp = nullptr;
+
+ /* Note: only ClipPath is processed in update() step */
+ if (compTarget && compMethod != CompositeMethod::ClipPath) {
+ uint32_t x, y, w, h;
+ if (!compTarget->pImpl->bounds(renderer, &x, &y, &w, &h)) return false;
+ cmp = renderer.addCompositor(compMethod, x, y, w, h, 255);
+ compTarget->pImpl->render(renderer);
+ }
+
+ auto ret = smethod->render(renderer);
+
+ renderer.delCompositor(cmp);
+
+ return ret;
}
Paint* duplicate()
bool composite(Paint* target, CompositeMethod method)
{
if (!target && method != CompositeMethod::None) return false;
+ if (target && method == CompositeMethod::None) return false;
compTarget = target;
compMethod = method;
return true;
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
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;
+}
\ No newline at end of file
Paint* paint = nullptr;
uint32_t *pixels = nullptr;
Picture *picture = nullptr;
- void *edata = nullptr; //engine data
+ void *rdata = nullptr; //engine data
float w = 0, h = 0;
bool resizing = false;
return true;
}
else if (pixels) {
- return renderer.dispose(edata);
+ return renderer.dispose(rdata);
}
return false;
}
}
}
if (!pixels) {
- pixels = (uint32_t*)loader->pixels();
+ pixels = const_cast<uint32_t*>(loader->pixels());
if (pixels) return RenderUpdateFlag::Image;
}
}
return RenderUpdateFlag::None;
}
- void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag)
+ void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
{
- uint32_t flag = reload();
+ auto flag = reload();
- if (pixels) edata = renderer.prepare(*picture, edata, pixels, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
+ if (pixels) rdata = renderer.prepare(*picture, rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
else if (paint) {
if (resizing) resize();
- edata = paint->pImpl->update(renderer, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
+ rdata = paint->pImpl->update(renderer, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
}
- return edata;
+ return rdata;
}
bool render(RenderMethod &renderer)
{
- if (pixels) return renderer.render(*picture, edata);
+ if (pixels) return renderer.renderImage(rdata, nullptr);
else if (paint) return paint->pImpl->render(renderer);
return false;
}
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
- if (edata) return renderer.renderRegion(edata, x, y, w, h);
- if (paint) paint->pImpl->bounds(renderer, x, y, w, h);
+ if (rdata) return renderer.renderRegion(rdata, x, y, w, h);
+ if (paint) return paint->pImpl->bounds(renderer, x, y, w, h);
return false;
}
uint32_t cs;
};
-struct Composite {
- void* edata;
- CompositeMethod method;
-};
+using RenderData = void*;
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, All = 64};
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
};
-
class RenderMethod
{
public:
virtual ~RenderMethod() {}
- virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0;
- virtual void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0;
- virtual void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
- virtual bool endComposite(void* ctx, uint32_t opacity) = 0;
- virtual bool dispose(void *data) = 0;
+ virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
+ virtual RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
+ virtual void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) = 0;
+ virtual bool delCompositor(void* cmp) = 0;
+ virtual bool dispose(RenderData data) = 0;
virtual bool preRender() = 0;
- virtual bool render(const Shape& shape, void *data) = 0;
- virtual bool render(const Picture& picture, void *data) = 0;
+ virtual bool renderShape(RenderData data, void* cmp) = 0;
+ virtual bool renderImage(RenderData data, void* cmp) = 0;
virtual bool postRender() = 0;
- virtual bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
+ virtual bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
virtual bool clear() = 0;
virtual bool sync() = 0;
};
return true;
}
- void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flag)
+ void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag)
{
this->opacity = opacity;
/* Overriding opacity value. If this scene is half-translucent,
It must do intermeidate composition with that opacity value. */
- if (opacity < 255 && opacity > 0) opacity = 255;
-
- /* FXIME: it requires to return list of children engine data
- This is necessary for scene composition */
- void* edata = nullptr;
+ if (opacity > 0) opacity = 255;
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
- edata = (*paint)->pImpl->update(renderer, transform, opacity, compList, static_cast<uint32_t>(flag));
+ (*paint)->pImpl->update(renderer, transform, opacity, clips, static_cast<uint32_t>(flag));
}
- return edata;
+ /* FXIME: it requires to return list of children engine data
+ This is necessary for scene composition */
+ return nullptr;
}
bool render(RenderMethod& renderer)
{
- void* ctx = nullptr;
+ void* cmp = nullptr;
- //Half translucent. This requires intermediate composition.
- if (opacity < 255 && opacity > 0) {
+ //Half translucent. This condition requires intermediate composition.
+ if (opacity < 255 && opacity > 0 && (paints.count > 1)) {
uint32_t x, y, w, h;
if (!bounds(renderer, &x, &y, &w, &h)) return false;
- ctx = renderer.beginComposite(x, y, w, h);
+ //CompositeMethod::None is used for a default alpha blending
+ cmp = renderer.addCompositor(CompositeMethod::None, x, y, w, h, opacity);
}
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
if (!(*paint)->pImpl->render(renderer)) return false;
}
- if (ctx) return renderer.endComposite(ctx, opacity);
+ if (cmp) renderer.delCompositor(cmp);
return true;
}
ShapeStroke *stroke = nullptr;
uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
FillRule rule = FillRule::Winding;
- void *edata = nullptr; //engine data
+ RenderData rdata = nullptr; //engine data
Shape *shape = nullptr;
uint32_t flag = RenderUpdateFlag::None;
bool dispose(RenderMethod& renderer)
{
- return renderer.dispose(edata);
+ return renderer.dispose(rdata);
}
bool render(RenderMethod& renderer)
{
- return renderer.render(*shape, edata);
+ return renderer.renderShape(rdata, nullptr);
}
- void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag)
+ void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
{
- this->edata = renderer.prepare(*shape, this->edata, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
+ this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
flag = RenderUpdateFlag::None;
- return this->edata;
+ return this->rdata;
}
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
- return renderer.renderRegion(edata, x, y, w, h);
+ return renderer.renderRegion(rdata, x, y, w, h);
}
bool bounds(float* x, float* y, float* w, float* h)