mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-11 23:21:55 +00:00
sw_engine renderer: support scene opacity composition
this is an additional enhancement of af8c278c5e
Now scene opacity composition is supported.
Also, this implementaion fixes an incorrect scene bounding box computation.
Plus, adding stroking feathering to shape bounding box size.
This commit is contained in:
parent
20de2bfc15
commit
77e8a195b4
8 changed files with 237 additions and 68 deletions
|
@ -8,61 +8,79 @@ void tvgDrawCmds(tvg::Canvas* canvas)
|
||||||
{
|
{
|
||||||
if (!canvas) return;
|
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
|
//Prepare Circle
|
||||||
auto shape1 = tvg::Shape::gen();
|
auto shape1 = tvg::Shape::gen();
|
||||||
shape1->appendCircle(400, 400, 250, 250);
|
shape1->appendCircle(400, 400, 250, 250);
|
||||||
shape1->fill(255, 255, 0, 255);
|
shape1->fill(255, 255, 0, 255);
|
||||||
canvas->push(move(shape1));
|
scene->push(move(shape1));
|
||||||
|
|
||||||
//Create a Scene
|
//Round rectangle
|
||||||
auto scene = tvg::Scene::gen();
|
|
||||||
scene->opacity(127); //Apply opacity to scene (0 - 255)
|
|
||||||
scene->reserve(2);
|
|
||||||
|
|
||||||
//Star
|
|
||||||
auto shape2 = tvg::Shape::gen();
|
auto shape2 = tvg::Shape::gen();
|
||||||
|
shape2->appendRect(450, 100, 200, 200, 50, 50);
|
||||||
//Appends Paths
|
shape2->fill(0, 255, 0, 255);
|
||||||
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(10);
|
||||||
shape2->stroke(255, 255, 255, 255);
|
shape2->stroke(255, 255, 255, 255);
|
||||||
shape2->opacity(127);
|
|
||||||
|
|
||||||
scene->push(move(shape2));
|
scene->push(move(shape2));
|
||||||
|
|
||||||
//Circle
|
|
||||||
|
//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 shape3 = tvg::Shape::gen();
|
auto shape3 = tvg::Shape::gen();
|
||||||
|
|
||||||
|
//Appends Paths
|
||||||
|
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);
|
||||||
|
|
||||||
|
scene2->push(move(shape3));
|
||||||
|
|
||||||
|
//Circle
|
||||||
|
auto shape4 = tvg::Shape::gen();
|
||||||
|
|
||||||
auto cx = 550.0f;
|
auto cx = 550.0f;
|
||||||
auto cy = 550.0f;
|
auto cy = 550.0f;
|
||||||
auto radius = 125.0f;
|
auto radius = 125.0f;
|
||||||
auto halfRadius = radius * 0.552284f;
|
auto halfRadius = radius * 0.552284f;
|
||||||
|
|
||||||
//Append Paths
|
//Append Paths
|
||||||
shape3->moveTo(cx, cy - radius);
|
shape4->moveTo(cx, cy - radius);
|
||||||
shape3->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy);
|
shape4->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);
|
shape4->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);
|
shape4->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);
|
shape4->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius);
|
||||||
shape3->fill(255, 0, 0, 255);
|
shape4->fill(255, 0, 0, 255);
|
||||||
shape3->stroke(10);
|
shape4->stroke(10);
|
||||||
shape3->stroke(0, 0, 255, 255);
|
shape4->stroke(0, 0, 255, 255);
|
||||||
shape3->opacity(200);
|
shape4->opacity(200);
|
||||||
scene->push(move(shape3));
|
scene2->push(move(shape4));
|
||||||
|
|
||||||
//Draw the Scene onto the Canvas
|
//Draw the Scene onto the Canvas
|
||||||
canvas->push(move(scene));
|
canvas->push(move(scene2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,28 @@ bool GlRenderer::postRender()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
bool GlRenderer::render(const Shape& shape, void* data)
|
||||||
{
|
{
|
||||||
GlShape* sdata = static_cast<GlShape*>(data);
|
GlShape* sdata = static_cast<GlShape*>(data);
|
||||||
|
@ -140,6 +162,13 @@ 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 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)
|
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
|
//prepare shape data
|
||||||
|
|
|
@ -31,9 +31,13 @@ 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, vector<Composite>& compList, RenderUpdateFlag flags) override;
|
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;
|
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 preRender() override;
|
||||||
bool render(const Shape& shape, void *data) override;
|
bool render(const Shape& shape, void *data) override;
|
||||||
|
bool render(const Picture& picture, void *data) override;
|
||||||
bool postRender() override;
|
bool postRender() 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;
|
||||||
|
|
|
@ -30,6 +30,14 @@
|
||||||
static bool initEngine = false;
|
static bool initEngine = false;
|
||||||
static uint32_t rendererCnt = 0;
|
static uint32_t rendererCnt = 0;
|
||||||
|
|
||||||
|
struct CompositeCtx
|
||||||
|
{
|
||||||
|
SwSurface surface;
|
||||||
|
SwSurface* recover;
|
||||||
|
SwImage image;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct SwTask : Task
|
struct SwTask : Task
|
||||||
{
|
{
|
||||||
Matrix* transform = nullptr;
|
Matrix* transform = nullptr;
|
||||||
|
@ -219,6 +227,12 @@ bool SwRenderer::clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SwRenderer::sync()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
|
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;
|
if (!buffer || stride == 0 || w == 0 || h == 0) return false;
|
||||||
|
@ -268,6 +282,80 @@ bool SwRenderer::render(TVG_UNUSED const Picture& picture, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
bool SwRenderer::prepareComposite(const SwShapeTask* task, SwImage* image)
|
||||||
{
|
{
|
||||||
if (!compSurface) {
|
if (!compSurface) {
|
||||||
|
|
|
@ -38,13 +38,16 @@ class SwRenderer : public RenderMethod
|
||||||
public:
|
public:
|
||||||
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, vector<Composite>& compList, RenderUpdateFlag flags) override;
|
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* 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 dispose(void *data) override;
|
||||||
bool preRender() override;
|
bool preRender() override;
|
||||||
bool postRender() 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 clear() override;
|
||||||
bool render(const Shape& shape, void *data) override;
|
bool render(const Shape& shape, void *data) override;
|
||||||
bool render(const Picture& picture, 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 SwRenderer* gen();
|
||||||
static bool init(uint32_t threads);
|
static bool init(uint32_t threads);
|
||||||
|
|
|
@ -65,15 +65,17 @@ class RenderMethod
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~RenderMethod() {}
|
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(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, vector<Composite>& compList, RenderUpdateFlag flags) = 0;
|
||||||
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 void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, vector<Composite>& compList, RenderUpdateFlag flags) = 0;
|
||||||
virtual bool dispose(TVG_UNUSED void *data) { return true; }
|
virtual void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
|
||||||
virtual bool preRender() { return true; }
|
virtual bool endComposite(void* ctx, uint32_t opacity) = 0;
|
||||||
virtual bool render(TVG_UNUSED const Shape& shape, TVG_UNUSED void *data) { return true; }
|
virtual bool dispose(void *data) = 0;
|
||||||
virtual bool render(TVG_UNUSED const Picture& picture, TVG_UNUSED void *data) { return true; }
|
virtual bool preRender() = 0;
|
||||||
virtual bool postRender() { return true; }
|
virtual bool render(const Shape& shape, void *data) = 0;
|
||||||
virtual bool clear() { return true; }
|
virtual bool render(const Picture& picture, void *data) = 0;
|
||||||
virtual bool sync() { return true; }
|
virtual bool postRender() = 0;
|
||||||
|
virtual bool clear() = 0;
|
||||||
|
virtual bool sync() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
struct Scene::Impl
|
struct Scene::Impl
|
||||||
{
|
{
|
||||||
vector<Paint*> paints;
|
vector<Paint*> paints;
|
||||||
|
uint32_t opacity;
|
||||||
|
|
||||||
bool dispose(RenderMethod& renderer)
|
bool dispose(RenderMethod& renderer)
|
||||||
{
|
{
|
||||||
|
@ -46,6 +47,12 @@ struct Scene::Impl
|
||||||
|
|
||||||
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, vector<Composite>& compList, RenderUpdateFlag flag)
|
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
|
/* 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;
|
void* edata = nullptr;
|
||||||
|
@ -59,45 +66,54 @@ struct Scene::Impl
|
||||||
|
|
||||||
bool render(RenderMethod &renderer)
|
bool render(RenderMethod &renderer)
|
||||||
{
|
{
|
||||||
//TODO: composition begin
|
void* ctx = nullptr;
|
||||||
//auto data = renderer.beginComp();
|
|
||||||
|
//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) {
|
for (auto paint : paints) {
|
||||||
if (!paint->pImpl->render(renderer)) return false;
|
if (!paint->pImpl->render(renderer)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: composition end
|
if (ctx) return renderer.endComposite(ctx, opacity);
|
||||||
//renderer.endComp(edata);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bounds(float* px, float* py, float* pw, float* ph)
|
bool bounds(float* px, float* py, float* pw, float* ph)
|
||||||
{
|
{
|
||||||
auto x = FLT_MAX;
|
if (paints.size() == 0) return false;
|
||||||
auto y = FLT_MAX;
|
|
||||||
auto w = 0.0f;
|
auto x1 = FLT_MAX;
|
||||||
auto h = 0.0f;
|
auto y1 = FLT_MAX;
|
||||||
|
auto x2 = 0.0f;
|
||||||
|
auto y2 = 0.0f;
|
||||||
|
|
||||||
for (auto paint : paints) {
|
for (auto paint : paints) {
|
||||||
auto x2 = FLT_MAX;
|
auto x = FLT_MAX;
|
||||||
auto y2 = FLT_MAX;
|
auto y = FLT_MAX;
|
||||||
auto w2 = 0.0f;
|
auto w = 0.0f;
|
||||||
auto h2 = 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
|
//Merge regions
|
||||||
if (x2 < x) x = x2;
|
if (x < x1) x1 = x;
|
||||||
if (x + w < x2 + w2) w = (x2 + w2) - x;
|
if (x2 < x + w) x2 = (x + w);
|
||||||
if (y2 < y) y = y2;
|
if (y < y1) y1 = y;
|
||||||
if (y + h < y2 + h2) h = (y2 + h2) - y;
|
if (y2 < y + h) y2 = (y + h);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (px) *px = x;
|
if (px) *px = x1;
|
||||||
if (py) *py = y;
|
if (py) *py = y1;
|
||||||
if (pw) *pw = w;
|
if (pw) *pw = (x2 - x1);
|
||||||
if (ph) *ph = h;
|
if (ph) *ph = (y2 - y1);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,7 +232,16 @@ struct Shape::Impl
|
||||||
|
|
||||||
bool bounds(float* x, float* y, float* w, float* h)
|
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)
|
bool strokeWidth(float width)
|
||||||
|
|
Loading…
Add table
Reference in a new issue