{
if (!canvas) return;
+ //Create a Scene
+ auto scene = tvg::Scene::gen();
+ scene->opacity(175); //Apply opacity to scene (0 - 255)
+ scene->reserve(2);
+
//Prepare Circle
auto shape1 = tvg::Shape::gen();
shape1->appendCircle(400, 400, 250, 250);
shape1->fill(255, 255, 0, 255);
- canvas->push(move(shape1));
+ scene->push(move(shape1));
+
+ //Round rectangle
+ auto shape2 = tvg::Shape::gen();
+ shape2->appendRect(450, 100, 200, 200, 50, 50);
+ shape2->fill(0, 255, 0, 255);
+ shape2->stroke(10);
+ shape2->stroke(255, 255, 255, 255);
+ scene->push(move(shape2));
- //Create a Scene
- auto scene = tvg::Scene::gen();
- scene->opacity(127); //Apply opacity to scene (0 - 255)
- scene->reserve(2);
+
+ //Draw the Scene onto the Canvas
+ canvas->push(move(scene));
+
+ //Create a Scene 2
+ auto scene2 = tvg::Scene::gen();
+ scene2->opacity(127); //Apply opacity to scene (0 - 255)
+ scene2->scale(1.2);
+ scene2->reserve(2);
//Star
- auto shape2 = tvg::Shape::gen();
+ auto shape3 = tvg::Shape::gen();
//Appends Paths
- shape2->moveTo(199, 34);
- shape2->lineTo(253, 143);
- shape2->lineTo(374, 160);
- shape2->lineTo(287, 244);
- shape2->lineTo(307, 365);
- shape2->lineTo(199, 309);
- shape2->lineTo(97, 365);
- shape2->lineTo(112, 245);
- shape2->lineTo(26, 161);
- shape2->lineTo(146, 143);
- shape2->close();
- shape2->fill(0, 0, 255, 255);
- shape2->stroke(10);
- shape2->stroke(255, 255, 255, 255);
- shape2->opacity(127);
+ shape3->moveTo(199, 34);
+ shape3->lineTo(253, 143);
+ shape3->lineTo(374, 160);
+ shape3->lineTo(287, 244);
+ shape3->lineTo(307, 365);
+ shape3->lineTo(199, 309);
+ shape3->lineTo(97, 365);
+ shape3->lineTo(112, 245);
+ shape3->lineTo(26, 161);
+ shape3->lineTo(146, 143);
+ shape3->close();
+ shape3->fill(0, 0, 255, 255);
+ shape3->stroke(10);
+ shape3->stroke(255, 255, 255, 255);
+ shape3->opacity(127);
- scene->push(move(shape2));
+ scene2->push(move(shape3));
//Circle
- auto shape3 = tvg::Shape::gen();
+ auto shape4 = tvg::Shape::gen();
auto cx = 550.0f;
auto cy = 550.0f;
auto halfRadius = radius * 0.552284f;
//Append Paths
- shape3->moveTo(cx, cy - radius);
- shape3->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy);
- shape3->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius);
- shape3->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy);
- shape3->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius);
- shape3->fill(255, 0, 0, 255);
- shape3->stroke(10);
- shape3->stroke(0, 0, 255, 255);
- shape3->opacity(200);
- scene->push(move(shape3));
+ shape4->moveTo(cx, cy - radius);
+ shape4->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy);
+ shape4->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius);
+ shape4->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy);
+ shape4->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius);
+ shape4->fill(255, 0, 0, 255);
+ shape4->stroke(10);
+ shape4->stroke(0, 0, 255, 255);
+ shape4->opacity(200);
+ scene2->push(move(shape4));
//Draw the Scene onto the Canvas
- canvas->push(move(scene));
+ canvas->push(move(scene2));
}
}
+void* GlRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ //TODO: Prepare frameBuffer & Setup render target for composition
+ return nullptr;
+}
+
+
+bool GlRenderer::endComposite(void* ctx, uint32_t opacity)
+{
+ //TODO: Composite Framebuffer to main surface
+ return false;
+}
+
+
+bool GlRenderer::render(const Picture& picture, void *data)
+{
+ //TODO Draw Bitmap Image
+
+ return true;
+}
+
+
bool GlRenderer::render(const Shape& shape, void* data)
{
GlShape* sdata = static_cast<GlShape*>(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 vector<Composite>& compList, 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, vector<Composite>& compList, RenderUpdateFlag flags)
{
//prepare shape data
Surface surface = {nullptr, 0, 0, 0};
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, vector<Composite>& compList, RenderUpdateFlag flags) override;
+ void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, vector<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;
bool preRender() override;
bool render(const Shape& shape, void *data) override;
+ bool render(const Picture& picture, void *data) override;
bool postRender() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
bool sync() override;
static bool initEngine = false;
static uint32_t rendererCnt = 0;
+struct CompositeCtx
+{
+ SwSurface surface;
+ SwSurface* recover;
+ SwImage image;
+};
+
+
struct SwTask : Task
{
Matrix* transform = nullptr;
}
+bool SwRenderer::sync()
+{
+ return true;
+}
+
+
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
{
if (!buffer || stride == 0 || w == 0 || h == 0) return false;
}
+void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ auto ctx = new CompositeCtx;
+ if (!ctx) return nullptr;
+
+ //SwImage, Optimize Me: Surface size from MainSurface(WxH) to Parameter W x H
+ ctx->image.data = (uint32_t*) malloc(sizeof(uint32_t) * mainSurface->w * mainSurface->h);
+ if (!ctx->image.data) {
+ delete(ctx);
+ return nullptr;
+ }
+
+ //Boundary Check
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ if (x + w > mainSurface->w) w = (mainSurface->w - x);
+ if (y + h > mainSurface->h) h = (mainSurface->h - y);
+
+ //FIXME: Should be removed if xywh is proper.
+ x = 0;
+ y = 0;
+ w = mainSurface->w;
+ h = mainSurface->h;
+
+ ctx->image.bbox.min.x = x;
+ ctx->image.bbox.min.y = y;
+ ctx->image.bbox.max.x = x + w;
+ ctx->image.bbox.max.y = y + h;
+ ctx->image.w = mainSurface->w;
+ ctx->image.h = mainSurface->h;
+
+ //Inherits attributes from main surface
+ ctx->surface.comp = mainSurface->comp;
+ ctx->surface.stride = mainSurface->w;
+ ctx->surface.cs = mainSurface->cs;
+
+ //We know partial clear region
+ ctx->surface.buffer = ctx->image.data + (ctx->surface.stride * y + x);
+ ctx->surface.w = w;
+ ctx->surface.h = h;
+
+ rasterClear(&ctx->surface);
+
+ //Recover context
+ ctx->surface.buffer = ctx->image.data;
+ ctx->surface.w = ctx->image.w;
+ ctx->surface.h = ctx->image.h;
+
+ //Switch render target
+ ctx->recover = mainSurface;
+ mainSurface = &ctx->surface;
+
+ return ctx;
+}
+
+
+bool SwRenderer::endComposite(void* p, uint32_t opacity)
+{
+ if (!p) return false;
+ auto ctx = static_cast<CompositeCtx*>(p);
+
+ //Recover render target
+ mainSurface = ctx->recover;
+
+ auto ret = rasterImage(mainSurface, &ctx->image, nullptr, opacity);
+
+ //Free resources
+ free(ctx->image.data);
+ delete(ctx);
+
+ return ret;
+}
+
+
bool SwRenderer::prepareComposite(const SwShapeTask* task, SwImage* image)
{
if (!compSurface) {
public:
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, vector<Composite>& compList, RenderUpdateFlag flags) override;
void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, vector<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;
bool preRender() override;
bool postRender() override;
- bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
bool clear() override;
bool render(const Shape& shape, void *data) override;
bool render(const Picture& picture, void *data) override;
+ bool sync() override;
+ bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
static SwRenderer* gen();
static bool init(uint32_t threads);
{
public:
virtual ~RenderMethod() {}
- virtual void* prepare(TVG_UNUSED const Shape& shape, TVG_UNUSED void* data, TVG_UNUSED const RenderTransform* transform, uint32_t opacity, TVG_UNUSED vector<Composite>& compList, TVG_UNUSED RenderUpdateFlag flags) { return nullptr; }
- virtual void* 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 vector<Composite>& compList, TVG_UNUSED RenderUpdateFlag flags) { return nullptr; }
- virtual bool dispose(TVG_UNUSED void *data) { return true; }
- virtual bool preRender() { return true; }
- virtual bool render(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return true; }
- virtual bool render(TVG_UNUSED const Picture& picture, TVG_UNUSED void *data) { return true; }
- virtual bool postRender() { return true; }
- virtual bool clear() { return true; }
- virtual bool sync() { return true; }
+ virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, vector<Composite>& compList, RenderUpdateFlag flags) = 0;
+ virtual void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, vector<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 bool preRender() = 0;
+ virtual bool render(const Shape& shape, void *data) = 0;
+ virtual bool render(const Picture& picture, void *data) = 0;
+ virtual bool postRender() = 0;
+ virtual bool clear() = 0;
+ virtual bool sync() = 0;
};
}
struct Scene::Impl
{
vector<Paint*> paints;
+ uint32_t opacity;
bool dispose(RenderMethod& renderer)
{
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, vector<Composite>& compList, 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;
bool render(RenderMethod &renderer)
{
- //TODO: composition begin
- //auto data = renderer.beginComp();
+ void* ctx = nullptr;
+
+ //Half translucent. This requires intermediate composition.
+ if (opacity < 255 && opacity > 0) {
+ //FIXME: Get Render Boundary of Shapes.
+ //float x, y, w, h;
+ //if (!bounds(&x, &y, &w, &h)) return false;
+ //ctx = renderer.beginComposite(roundf(x), roundf(y), roundf(w), roundf(h));
+ ctx = renderer.beginComposite(0, 0, 0, 0);
+ }
for (auto paint : paints) {
if (!paint->pImpl->render(renderer)) return false;
- }
+ }
- //TODO: composition end
- //renderer.endComp(edata);
+ if (ctx) return renderer.endComposite(ctx, opacity);
return true;
}
bool bounds(float* px, float* py, float* pw, float* ph)
{
- auto x = FLT_MAX;
- auto y = FLT_MAX;
- auto w = 0.0f;
- auto h = 0.0f;
+ if (paints.size() == 0) return false;
+
+ auto x1 = FLT_MAX;
+ auto y1 = FLT_MAX;
+ auto x2 = 0.0f;
+ auto y2 = 0.0f;
for (auto paint : paints) {
- auto x2 = FLT_MAX;
- auto y2 = FLT_MAX;
- auto w2 = 0.0f;
- auto h2 = 0.0f;
+ auto x = FLT_MAX;
+ auto y = FLT_MAX;
+ auto w = 0.0f;
+ auto h = 0.0f;
- if (!paint->pImpl->bounds(&x2, &y2, &w2, &h2)) continue;
+ if (!paint->pImpl->bounds(&x, &y, &w, &h)) continue;
//Merge regions
- if (x2 < x) x = x2;
- if (x + w < x2 + w2) w = (x2 + w2) - x;
- if (y2 < y) y = y2;
- if (y + h < y2 + h2) h = (y2 + h2) - y;
+ if (x < x1) x1 = x;
+ if (x2 < x + w) x2 = (x + w);
+ if (y < y1) y1 = y;
+ if (y2 < y + h) y2 = (y + h);
}
- if (px) *px = x;
- if (py) *py = y;
- if (pw) *pw = w;
- if (ph) *ph = h;
+ if (px) *px = x1;
+ if (py) *py = y1;
+ if (pw) *pw = (x2 - x1);
+ if (ph) *ph = (y2 - y1);
return true;
}
bool bounds(float* x, float* y, float* w, float* h)
{
- return path.bounds(x, y, w, h);
+ auto ret = path.bounds(x, y, w, h);
+
+ //Stroke feathering
+ if (stroke) {
+ if (x) *x -= stroke->width * 0.5f;
+ if (y) *y -= stroke->width * 0.5f;
+ if (w) *w += stroke->width;
+ if (h) *h += stroke->width;
+ }
+ return ret;
}
bool strokeWidth(float width)