From b08d144dc98a1cf0b528351feb4586d1a5bf081c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 6 May 2020 01:37:50 +0900 Subject: [PATCH] common shape: introduce transformation matrix Paint supports translate, rotate, scale functions for transformation The origin of these transformation is center of the paint, thus you have to consider the center-aligned vertices if you'd like to use these transformation functions. This policy has been considered for scene transformation. Change-Id: I78b63d7965faec0ec5b9a98a7776993744534b54 --- inc/tizenvg.h | 9 ++--- src/lib/gl_engine/tvgGlRenderer.cpp | 10 ++++- src/lib/gl_engine/tvgGlRenderer.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRenderer.cpp | 6 +-- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 47 +++------------------- src/lib/tvgRenderCommon.h | 78 ++++++++++++++++++++++++++++++++++++- src/lib/tvgScene.cpp | 18 +++------ src/lib/tvgShape.cpp | 24 ++++++------ src/lib/tvgShapeImpl.h | 15 ++++++- test/testTransform.cpp | 9 +++-- test/testUpdate.cpp | 3 +- 13 files changed, 139 insertions(+), 86 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 63da89f..98b6faf 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -79,10 +79,9 @@ public: virtual int rotate(float degree) = 0; virtual int scale(float factor) = 0; + virtual int translate(float x, float y) = 0; virtual int bounds(float&x, float& y, float& w, float& h) const = 0; - virtual float scale() const = 0; - virtual float rotate() const = 0; }; @@ -141,13 +140,12 @@ public: int rotate(float degree) noexcept override; int scale(float factor) noexcept override; + int translate(float x, float y) noexcept override; size_t pathCommands(const PathCommand** cmds) const noexcept; size_t pathCoords(const Point** pts) const noexcept; int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; int bounds(float&x, float& y, float& w, float& h) const noexcept override; - float scale() const noexcept override; - float rotate() const noexcept override; static std::unique_ptr gen() noexcept; @@ -175,10 +173,9 @@ public: int rotate(float degree) noexcept override; int scale(float factor) noexcept override; + int translate(float x, float y) noexcept override; int bounds(float&x, float& y, float& w, float& h) const noexcept override; - float scale() const noexcept override; - float rotate() const noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 0b1a9c7..08a9c30 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data) } -void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); @@ -74,6 +74,14 @@ void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags assert(sdata); } + if (RenderUpdateFlag::Path) { + //TODO: Updated Vertices + } + + if (RenderUpdateFlag::Transform) { + //TODO: Updated Transform + } + //TODO: return sdata; diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index e9e5abe..4d6ba79 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -23,7 +23,7 @@ namespace tvg class GlRenderer : public RenderMethod { public: - void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool clear() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 00ff315..62a6b29 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -96,7 +96,7 @@ void shapeReset(SwShape& sdata); bool shapeGenOutline(const Shape& shape, SwShape& sdata); void shapeDelOutline(SwShape& sdata); bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); -bool shapeTransformOutline(const Shape& shape, SwShape& sdata); +void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform); SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index c9df96f..ce741ff 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } -void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(data); @@ -98,10 +98,10 @@ void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags if (alpha == 0) return sdata; //TODO: Threading - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { + if (flags & RenderUpdateFlag::Path || RenderUpdateFlag::Transform) { shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; - if (!shapeTransformOutline(shape, *sdata)) return sdata; + if (transform) shapeTransformOutline(shape, *sdata, *transform); SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; if (!shapeGenRle(shape, *sdata, clip)) return sdata; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index b299d70..3dfb076 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod public: Surface surface; - void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override; + void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 03be175..d7229dc 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -215,54 +215,19 @@ void _deleteRle(SwShape& sdata) /* External Class Implementation */ /************************************************************************/ -bool shapeTransformOutline(const Shape& shape, SwShape& sdata) +void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform) { - constexpr auto PI = 3.141592f; - - auto degree = shape.rotate(); - auto scale = shape.scale(); - bool rotateOn = false; - bool scaleOn = false; - - if (fabsf(degree) > FLT_EPSILON) rotateOn = true; - if (fabsf(scale - 1) > FLT_EPSILON) scaleOn = true; - - if (!rotateOn && !scaleOn) return true; - auto outline = sdata.outline; assert(outline); - float x, y, w, h; - shape.bounds(x, y, w, h); - - auto cx = x + w * 0.5f; - auto cy = y + h * 0.5f; - - float radian, cosVal, sinVal; - if (rotateOn) { - radian = degree / 180.0f * PI; - cosVal = cosf(radian); - sinVal = sinf(radian); - } - for(size_t i = 0; i < outline->ptsCnt; ++i) { - auto dx = static_cast(outline->pts[i].x >> 6) - cx; - auto dy = static_cast(outline->pts[i].y >> 6) - cy; - if (rotateOn) { - auto tx = (cosVal * dx - sinVal * dy); - auto ty = (sinVal * dx + cosVal * dy); - dx = tx; - dy = ty; - } - if (scaleOn) { - dx *= scale; - dy *= scale; - } - auto pt = Point{dx + cx, dy + cy}; + auto dx = static_cast(outline->pts[i].x >> 6); + auto dy = static_cast(outline->pts[i].y >> 6); + auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13; + auto ty = dx * transform.e21 + dy * transform.e22 + transform.e23; + auto pt = Point{tx + transform.e31, ty + transform.e32}; outline->pts[i] = TO_SWPOINT(&pt); } - - return true; } diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 9e8662b..b21c244 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -30,11 +30,87 @@ struct Surface enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8}; +struct RenderTransform +{ + float e11, e12, e13; + float e21, e22, e23; + float e31, e32, e33; + + void identity() + { + e11 = 1.0f; + e12 = 0.0f; + e13 = 0.0f; + e21 = 0.0f; + e22 = 1.0f; + e23 = 0.0f; + e31 = 0.0f; + e32 = 0.0f; + e33 = 1.0f; + } + + void rotate(float degree) + { + constexpr auto PI = 3.141592f; + + if (fabsf(degree) <= FLT_EPSILON) return; + + auto radian = degree / 180.0f * PI; + auto cosVal = cosf(radian); + auto sinVal = sinf(radian); + + auto t11 = e11 * cosVal + e12 * sinVal; + auto t12 = e11 * -sinVal + e12 * cosVal; + auto t21 = e21 * cosVal + e22 * sinVal; + auto t22 = e21 * -sinVal + e22 * cosVal; + auto t31 = e31 * cosVal + e32 * sinVal; + auto t32 = e31 * -sinVal + e32 * cosVal; + + e11 = t11; + e12 = t12; + e21 = t21; + e22 = t22; + e31 = t31; + e32 = t32; + } + + void translate(float x, float y) + { + e31 += x; + e32 += y; + } + + void scale(float factor) + { + e11 *= factor; + e22 *= factor; + e33 *= factor; + } + + RenderTransform& operator*=(const RenderTransform rhs) + { + e11 = e11 * rhs.e11 + e12 * rhs.e21 + e13 * rhs.e31; + e12 = e11 * rhs.e12 + e12 * rhs.e22 + e13 * rhs.e32; + e13 = e11 * rhs.e13 + e12 * rhs.e23 + e13 * rhs.e33; + + e21 = e21 * rhs.e11 + e22 * rhs.e21 + e23 * rhs.e31; + e22 = e21 * rhs.e12 + e22 * rhs.e22 + e23 * rhs.e32; + e23 = e21 * rhs.e13 + e22 * rhs.e23 + e23 * rhs.e33; + + e31 = e31 * rhs.e11 + e32 * rhs.e21 + e33 * rhs.e31; + e32 = e31 * rhs.e12 + e32 * rhs.e22 + e33 * rhs.e32; + e33 = e31 * rhs.e13 + e32 * rhs.e23 + e33 * rhs.e33; + + return *this; + } +}; + + class RenderMethod { public: virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) = 0; + virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0; virtual bool dispose(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 471d2ab..4b2a613 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -76,6 +76,12 @@ int Scene::rotate(float degree) noexcept } +int Scene::translate(float x, float y) noexcept +{ + return 0; +} + + int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept { auto impl = pImpl.get(); @@ -91,16 +97,4 @@ int Scene::bounds(float& x, float& y, float& w, float& h) const noexcept return 0; } - -float Scene::scale() const noexcept -{ - return 0; -} - - -float Scene::rotate() const noexcept -{ - return 0; -} - #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 272b194..6665a55 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -247,7 +247,7 @@ int Shape::scale(float factor) noexcept auto impl = pImpl.get(); assert(impl); - if (fabsf(factor) < FLT_EPSILON || fabsf(factor - impl->scale) <= FLT_EPSILON) return -1; + if (fabsf(factor - impl->scale) <= FLT_EPSILON) return -1; impl->scale = factor; impl->flag |= RenderUpdateFlag::Transform; @@ -270,32 +270,30 @@ int Shape::rotate(float degree) noexcept } -int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept +int Shape::translate(float x, float y) noexcept { auto impl = pImpl.get(); assert(impl); - if (!impl->bounds(x, y, w, h)) return -1; + if (fabsf(x - impl->x) <= FLT_EPSILON && fabsf(y - impl->y) <= FLT_EPSILON) return -1; + + impl->x = x; + impl->y = y; + impl->flag |= RenderUpdateFlag::Transform; return 0; } -float Shape::scale() const noexcept +int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept { auto impl = pImpl.get(); assert(impl); - return impl->scale; -} - - -float Shape::rotate() const noexcept -{ - auto impl = pImpl.get(); - assert(impl); + if (!impl->bounds(x, y, w, h)) return -1; - return impl->rotate; + return 0; } + #endif //_TVG_SHAPE_CPP_ diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 5894b1e..6b81dc0 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -41,6 +41,8 @@ struct Shape::Impl uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a float scale = 1; float rotate = 0; + float x = 0; + float y = 0; void *edata = nullptr; //engine data size_t flag = RenderUpdateFlag::None; @@ -67,8 +69,19 @@ struct Shape::Impl bool update(Shape& shape, RenderMethod& renderer) { - edata = renderer.prepare(shape, edata, static_cast(flag)); + if (flag & RenderUpdateFlag::Transform) { + RenderTransform transform; + transform.identity(); + transform.rotate(rotate); + transform.scale(scale); + transform.translate(x, y); + edata = renderer.prepare(shape, edata, &transform, static_cast(flag)); + } else { + edata = renderer.prepare(shape, edata, nullptr, static_cast(flag)); + } + flag = RenderUpdateFlag::None; + if (edata) return true; return false; } diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 1224299..faab048 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -23,11 +23,12 @@ void tvgtest() instead, you should consider not to interrupt this pointer life-cycle. */ pShape = shape.get(); - shape->appendRect(0, 0, 200, 200, 0); - shape->appendRect(100, 100, 300, 300, 100); - shape->appendCircle(400, 400, 100, 100); - shape->appendCircle(400, 500, 170, 100); + shape->appendRect(-285, -300, 200, 200, 0); + shape->appendRect(-185, -200, 300, 300, 100); + shape->appendCircle(115, 100, 100, 100); + shape->appendCircle(115, 200, 170, 100); shape->fill(255, 255, 255, 255); + shape->translate(285, 300); canvas->push(move(shape)); diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index d941e26..453b47c 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -33,8 +33,9 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres //Shape auto shape = tvg::Shape::gen(); - shape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + shape->appendRect(-100, -100, 200, 200, (100 * progress)); shape->fill(rand()%255, rand()%255, rand()%255, 255); + shape->translate(800 * progress, 800 * progress); shape->scale(1 - 0.75 * progress); shape->rotate(360 * progress); -- 2.7.4