common shape: introduce transformation matrix 64/232464/2
authorHermet Park <chuneon.park@samsung.com>
Tue, 5 May 2020 16:37:50 +0000 (01:37 +0900)
committerHermet Park <chuneon.park@samsung.com>
Tue, 5 May 2020 17:05:09 +0000 (02:05 +0900)
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

13 files changed:
inc/tizenvg.h
src/lib/gl_engine/tvgGlRenderer.cpp
src/lib/gl_engine/tvgGlRenderer.h
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRenderer.h
src/lib/sw_engine/tvgSwShape.cpp
src/lib/tvgRenderCommon.h
src/lib/tvgScene.cpp
src/lib/tvgShape.cpp
src/lib/tvgShapeImpl.h
test/testTransform.cpp
test/testUpdate.cpp

index 63da89f..98b6faf 100644 (file)
@@ -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<Shape> 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<Scene> gen() noexcept;
 
index 0b1a9c7..08a9c30 100644 (file)
@@ -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<GlShape*>(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;
index e9e5abe..4d6ba79 100644 (file)
@@ -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;
index 00ff315..62a6b29 100644 (file)
@@ -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);
index c9df96f..ce741ff 100644 (file)
@@ -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<SwShape*>(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<SwCoord>(surface.w), static_cast<SwCoord>(surface.h)};
         if (!shapeGenRle(shape, *sdata, clip)) return sdata;
index b299d70..3dfb076 100644 (file)
@@ -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);
index 03be175..d7229dc 100644 (file)
@@ -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<float>(outline->pts[i].x >> 6) - cx;
-        auto dy = static_cast<float>(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<float>(outline->pts[i].x >> 6);
+        auto dy = static_cast<float>(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;
 }
 
 
index 9e8662b..b21c244 100644 (file)
@@ -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;
index 471d2ab..4b2a613 100644 (file)
@@ -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
index 272b194..6665a55 100644 (file)
@@ -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_
index 5894b1e..6b81dc0 100644 (file)
@@ -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<RenderUpdateFlag>(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<RenderUpdateFlag>(flag));
+        } else {
+            edata = renderer.prepare(shape, edata, nullptr, static_cast<RenderUpdateFlag>(flag));
+        }
+
         flag = RenderUpdateFlag::None;
+
         if (edata) return true;
         return false;
     }
index 1224299..faab048 100644 (file)
@@ -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));
 
index d941e26..453b47c 100644 (file)
@@ -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);