common: support Scene Transform 14/233614/2
authorHermet Park <chuneon.park@samsung.com>
Sun, 17 May 2020 07:50:19 +0000 (16:50 +0900)
committerHermet Park <chuneon.park@samsung.com>
Sun, 17 May 2020 07:50:47 +0000 (16:50 +0900)
this contains testSceneTransform example

Change-Id: I460b05dc8bc4a842e26e950c800c5c35f8d3da7f

14 files changed:
.gitignore
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/tvgCanvasImpl.h
src/lib/tvgRenderCommon.h
src/lib/tvgScene.cpp
src/lib/tvgSceneImpl.h
src/lib/tvgShapeImpl.h
test/makefile
test/testSceneTransform.cpp [new file with mode: 0644]

index 2917573..6210eb8 100644 (file)
@@ -11,3 +11,4 @@ testUpdate
 testDirectUpdate
 testScene
 testTransform
+testSceneTransform
index 792e524..48a0ee5 100644 (file)
@@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data)
 }
 
 
-void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags)
+void* GlRenderer::prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags)
 {
     //prepare shape data
     GlShape* sdata = static_cast<GlShape*>(data);
index 4d6ba79..557f9e7 100644 (file)
@@ -23,7 +23,7 @@ namespace tvg
 class GlRenderer : public RenderMethod
 {
 public:
-    void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
+    void* prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags) override;
     bool dispose(const Shape& shape, void *data) override;
     bool render(const Shape& shape, void *data) override;
     bool clear() override;
index 62a6b29..3068b9b 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);
-void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform);
+void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderMatrix& 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 36e367b..2d97445 100644 (file)
@@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data)
     return true;
 }
 
-void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags)
+void* SwRenderer::prepare(const Shape& shape, void* data, const RenderMatrix* transform, RenderUpdateFlag flags)
 {
     //prepare shape data
     SwShape* sdata = static_cast<SwShape*>(data);
index 3dfb076..4c0a7ba 100644 (file)
@@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod
 public:
     Surface surface;
 
-    void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
+    void* prepare(const Shape& shape, void* data, const RenderMatrix* 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 d7229dc..efad932 100644 (file)
@@ -215,7 +215,7 @@ void _deleteRle(SwShape& sdata)
 /* External Class Implementation                                        */
 /************************************************************************/
 
-void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform)
+void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderMatrix& transform)
 {
     auto outline = sdata.outline;
     assert(outline);
index 20a5efd..afa2a0b 100644 (file)
@@ -71,9 +71,9 @@ struct Canvas::Impl
 
         for(auto paint: paints) {
             if (auto scene = dynamic_cast<Scene*>(paint)) {
-                if (!SCENE_IMPL->update(*renderer)) return -1;
+                if (!SCENE_IMPL->update(*renderer, nullptr)) return -1;
             } else if (auto shape = dynamic_cast<Shape*>(paint)) {
-                if (!SHAPE_IMPL->update(*shape, *renderer)) return -1;
+                if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return -1;
             }
         }
         return 0;
index a3bfcb6..0ad1d55 100644 (file)
@@ -30,13 +30,85 @@ struct Surface
 
 enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8};
 
-struct RenderTransform
+struct RenderMatrix
 {
     //3x3 Matrix Elements
     float e11, e12, e13;
     float e21, e22, e23;
     float e31, e32, e33;
 
+    static void rotate(RenderMatrix* out, 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 = out->e11 * cosVal + out->e12 * sinVal;
+        auto t12 = out->e11 * -sinVal + out->e12 * cosVal;
+        auto t21 = out->e21 * cosVal + out->e22 * sinVal;
+        auto t22 = out->e21 * -sinVal + out->e22 * cosVal;
+        auto t31 = out->e31 * cosVal + out->e32 * sinVal;
+        auto t32 = out->e31 * -sinVal + out->e32 * cosVal;
+
+        out->e11 = t11;
+        out->e12 = t12;
+        out->e21 = t21;
+        out->e22 = t22;
+        out->e31 = t31;
+        out->e32 = t32;
+    }
+
+    static void scale(RenderMatrix* out, float factor)
+    {
+        out->e11 *= factor;
+        out->e22 *= factor;
+        out->e33 *= factor;
+    }
+
+    static void identity(RenderMatrix* out)
+    {
+        out->e11 = 1.0f;
+        out->e12 = 0.0f;
+        out->e13 = 0.0f;
+        out->e21 = 0.0f;
+        out->e22 = 1.0f;
+        out->e23 = 0.0f;
+        out->e31 = 0.0f;
+        out->e32 = 0.0f;
+        out->e33 = 1.0f;
+    }
+
+    static void translate(RenderMatrix* out, float x, float y)
+    {
+        out->e31 += x;
+        out->e32 += y;
+    }
+
+    static void multiply(const RenderMatrix* lhs, const RenderMatrix* rhs, RenderMatrix* out)
+    {
+        assert(lhs && rhs && out);
+
+        out->e11 = lhs->e11 * rhs->e11 + lhs->e12 * rhs->e21 + lhs->e13 * rhs->e31;
+        out->e12 = lhs->e11 * rhs->e12 + lhs->e12 * rhs->e22 + lhs->e13 * rhs->e32;
+        out->e13 = lhs->e11 * rhs->e13 + lhs->e12 * rhs->e23 + lhs->e13 * rhs->e33;
+
+        out->e21 = lhs->e21 * rhs->e11 + lhs->e22 * rhs->e21 + lhs->e23 * rhs->e31;
+        out->e22 = lhs->e21 * rhs->e12 + lhs->e22 * rhs->e22 + lhs->e23 * rhs->e32;
+        out->e23 = lhs->e21 * rhs->e13 + lhs->e22 * rhs->e23 + lhs->e23 * rhs->e33;
+
+        out->e31 = lhs->e31 * rhs->e11 + lhs->e32 * rhs->e21 + lhs->e33 * rhs->e31;
+        out->e32 = lhs->e31 * rhs->e12 + lhs->e32 * rhs->e22 + lhs->e33 * rhs->e32;
+        out->e33 = lhs->e31 * rhs->e13 + lhs->e32 * rhs->e23 + lhs->e33 * rhs->e33;
+    }
+};
+
+struct RenderTransform
+{
+    RenderMatrix m;
     float x = 0.0f;
     float y = 0.0f;
     float degree = 0.0f;  //rotation degree
@@ -44,74 +116,19 @@ struct RenderTransform
 
     bool update()
     {
-        constexpr auto PI = 3.141592f;
-
         //Init Status
         if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON &&
             fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) {
             return false;
         }
 
-        //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;
-
-        //rotation
-        if (fabsf(degree) > FLT_EPSILON) {
-            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;
-        }
-
-        //scale
-        e11 *= factor;
-        e22 *= factor;
-        e33 *= factor;
-
-        //translate
-        e31 += x;
-        e32 += y;
+        RenderMatrix::identity(&m);
+        RenderMatrix::scale(&m, factor);
+        RenderMatrix::rotate(&m, degree);
+        RenderMatrix::translate(&m, x, y);
 
         return true;
     }
-
-    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;
-    }
 };
 
 
@@ -119,7 +136,7 @@ class RenderMethod
 {
 public:
     virtual ~RenderMethod() {}
-    virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0;
+    virtual void* prepare(const Shape& shape, void* data, const RenderMatrix* 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 4b2a613..dba9637 100644 (file)
@@ -64,21 +64,30 @@ int Scene::reserve(size_t size) noexcept
 }
 
 
-int Scene::scale(float scaleFacator) noexcept
+int Scene::scale(float factor) noexcept
 {
-    return 0;
+    auto impl = pImpl.get();
+    assert(impl);
+
+    return impl->scale(factor);
 }
 
 
 int Scene::rotate(float degree) noexcept
 {
-    return 0;
+    auto impl = pImpl.get();
+    assert(impl);
+
+    return impl->rotate(degree);
 }
 
 
 int Scene::translate(float x, float y) noexcept
 {
-    return 0;
+    auto impl = pImpl.get();
+    assert(impl);
+
+    return impl->translate(x, y);
 }
 
 
index a2ce90d..4def223 100644 (file)
 struct Scene::Impl
 {
     vector<Paint*> paints;
+    RenderTransform *transform = nullptr;
+    size_t flag = RenderUpdateFlag::None;
 
     ~Impl()
     {
         //Are you sure clear() prior to this?
         assert(paints.empty());
+        if (transform) delete(transform);
     }
 
     bool clear(RenderMethod& renderer)
@@ -48,18 +51,44 @@ struct Scene::Impl
         return true;
     }
 
-    bool update(RenderMethod &renderer)
+    bool updateInternal(RenderMethod &renderer, const RenderMatrix* transform, size_t flag)
     {
         for(auto paint: paints) {
             if (auto scene = dynamic_cast<Scene*>(paint)) {
-                if (!SCENE_IMPL->update(renderer)) return false;
+                if (!SCENE_IMPL->update(renderer, transform, flag)) return false;
             } else if (auto shape = dynamic_cast<Shape*>(paint)) {
-                if (!SHAPE_IMPL->update(*shape, renderer)) return false;
+                if (!SHAPE_IMPL->update(*shape, renderer, transform, flag)) return false;
             }
         }
         return true;
     }
 
+    bool update(RenderMethod &renderer, const RenderMatrix* pTransform = nullptr, size_t pFlag = 0)
+    {
+        if (flag & RenderUpdateFlag::Transform) {
+            assert(transform);
+            if (!transform->update()) {
+                delete(transform);
+                transform = nullptr;
+            }
+        }
+
+        auto ret = true;
+
+        if (transform && pTransform) {
+            RenderMatrix outTransform;
+            RenderMatrix::multiply(pTransform, &transform->m, &outTransform);
+            ret = updateInternal(renderer, &outTransform, pFlag | flag);
+        } else {
+            auto outTransform = pTransform ? pTransform : &transform->m;
+            ret = updateInternal(renderer, outTransform, pFlag | flag);
+        }
+
+        flag = RenderUpdateFlag::None;
+
+        return ret;
+    }
+
     bool render(RenderMethod &renderer)
     {
         for(auto paint: paints) {
@@ -94,6 +123,52 @@ struct Scene::Impl
         }
         return true;
     }
+
+    bool scale(float factor)
+    {
+        if (transform) {
+            if (fabsf(factor - transform->factor) <= FLT_EPSILON) return -1;
+        } else {
+            if (fabsf(factor) <= FLT_EPSILON) return -1;
+            transform = new RenderTransform();
+            assert(transform);
+        }
+        transform->factor = factor;
+        flag |= RenderUpdateFlag::Transform;
+
+        return 0;
+    }
+
+    bool rotate(float degree)
+    {
+        if (transform) {
+            if (fabsf(degree - transform->degree) <= FLT_EPSILON) return -1;
+        } else {
+            if (fabsf(degree) <= FLT_EPSILON) return -1;
+            transform = new RenderTransform();
+            assert(transform);
+        }
+        transform->degree = degree;
+        flag |= RenderUpdateFlag::Transform;
+
+        return 0;
+    }
+
+    bool translate(float x, float y)
+    {
+        if (transform) {
+            if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return -1;
+        } else {
+            if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return -1;
+            transform = new RenderTransform();
+            assert(transform);
+        }
+        transform->x = x;
+        transform->y = y;
+        flag |= RenderUpdateFlag::Transform;
+
+        return 0;
+    }
 };
 
 #endif //_TVG_SCENE_IMPL_H_
\ No newline at end of file
index e552a3b..3087426 100644 (file)
@@ -66,7 +66,7 @@ struct Shape::Impl
         return renderer.render(shape, edata);
     }
 
-    bool update(Shape& shape, RenderMethod& renderer)
+    bool update(Shape& shape, RenderMethod& renderer, const RenderMatrix* pTransform = nullptr, size_t pFlag = 0)
     {
         if (flag & RenderUpdateFlag::Transform) {
             assert(transform);
@@ -75,7 +75,16 @@ struct Shape::Impl
                 transform = nullptr;
             }
         }
-        edata = renderer.prepare(shape, edata, transform, static_cast<RenderUpdateFlag>(flag));
+
+        if (transform && pTransform) {
+            RenderMatrix outTransform;
+            RenderMatrix::multiply(pTransform, &transform->m, &outTransform);
+            edata = renderer.prepare(shape, edata, &outTransform, static_cast<RenderUpdateFlag>(pFlag | flag));
+        } else {
+            auto outTransform = pTransform ? pTransform : &transform->m;
+            edata = renderer.prepare(shape, edata, outTransform, static_cast<RenderUpdateFlag>(pFlag | flag));
+        }
+
         flag = RenderUpdateFlag::None;
 
         if (edata) return true;
index e437084..50710e0 100644 (file)
@@ -9,3 +9,4 @@ all:
        gcc -o testDirectUpdate testDirectUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
        gcc -o testScene testScene.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
        gcc -o testTransform testTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
+       gcc -o testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp
new file mode 100644 (file)
index 0000000..622dafc
--- /dev/null
@@ -0,0 +1,168 @@
+#include <tizenvg.h>
+#include <Elementary.h>
+
+using namespace std;
+
+#define WIDTH 800
+#define HEIGHT 800
+
+static uint32_t buffer[WIDTH * HEIGHT];
+unique_ptr<tvg::SwCanvas> canvas = nullptr;
+tvg::Scene* pScene1 = nullptr;
+tvg::Scene* pScene2 = nullptr;
+
+void tvgtest()
+{
+    //Initialize TizenVG Engine
+    tvg::Engine::init();
+
+    //Create a Canvas
+    canvas = tvg::SwCanvas::gen();
+    canvas->target(buffer, WIDTH, WIDTH, HEIGHT);
+
+    //Create a Scene
+    auto scene = tvg::Scene::gen();
+    pScene1 = scene.get();
+    scene->reserve(3);   //reserve 3 shape nodes (optional)
+
+    //Prepare Round Rectangle
+    auto shape1 = tvg::Shape::gen();
+    shape1->appendRect(-235, -250, 400, 400, 50);      //x, y, w, h, cornerRadius
+    shape1->fill(0, 255, 0, 255);                //r, g, b, a
+    scene->push(move(shape1));
+
+    //Prepare Circle
+    auto shape2 = tvg::Shape::gen();
+    shape2->appendCircle(-165, -150, 200, 200);    //cx, cy, radiusW, radiusH
+    shape2->fill(255, 255, 0, 255);              //r, g, b, a
+    scene->push(move(shape2));
+
+    //Prepare Ellipse
+    auto shape3 = tvg::Shape::gen();
+    shape3->appendCircle(265, 250, 150, 100);    //cx, cy, radiusW, radiusH
+    shape3->fill(0, 255, 255, 255);              //r, g, b, a
+    scene->push(move(shape3));
+
+    scene->translate(350, 350);
+    scene->scale(0.7);
+
+    //Create another Scene
+    auto scene2 = tvg::Scene::gen();
+    pScene2 = scene2.get();
+    scene2->reserve(2);   //reserve 2 shape nodes (optional)
+
+#if 0
+    //Star
+    auto shape4 = tvg::Shape::gen();
+
+    //Appends Paths
+    shape4->moveTo(0, -114.5);
+    shape4->lineTo(54, -5.5);
+    shape4->lineTo(175, 11.5);
+    shape4->lineTo(88, 95.5);
+    shape4->lineTo(108, 216.5);
+    shape4->lineTo(0, 160.5);
+    shape4->lineTo(-102, 216.5);
+    shape4->lineTo(-87, 96.5);
+    shape4->lineTo(-173, 12.5);
+    shape4->lineTo(-53, -5.5);
+    shape4->close();
+    shape4->fill(0, 0, 127, 127);
+
+    float x, y, w, h;
+    shape4->bounds(x, y, w, h);
+    scene2->push(move(shape4));
+
+    //Circle
+    auto shape5 = tvg::Shape::gen();
+
+    auto cx = -150.0f;
+    auto cy = -150.0f;
+    auto radius = 125.0f;
+    auto halfRadius = radius * 0.552284f;
+
+    //Append Paths
+    shape5->moveTo(cx, cy - radius);
+    shape5->cubicTo(cx + halfRadius, cy - radius, cx + radius, cy - halfRadius, cx + radius, cy);
+    shape5->cubicTo(cx + radius, cy + halfRadius, cx + halfRadius, cy + radius, cx, cy+ radius);
+    shape5->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy);
+    shape5->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius);
+    shape5->fill(127, 0, 0, 127);
+    scene2->push(move(shape5));
+
+    scene2->translate(300, 300);
+
+    //Push scene2 onto the scene
+    scene->push(move(scene2));
+#endif
+    //Draw the Scene onto the Canvas
+    canvas->push(move(scene));
+
+    canvas->draw();
+    canvas->sync();
+
+    //Terminate TizenVG Engine
+    tvg::Engine::term();
+}
+
+void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress)
+{
+    /* Update scene directly.
+       You can update only necessary properties of this scene,
+       while retaining other properties. */
+
+    pScene1->rotate(360 * progress);
+
+    //Update shape for drawing (this may work asynchronously)
+    canvas->update(pScene1);
+
+    //Draw Next frames
+    canvas->draw();
+    canvas->sync();
+
+    //Update Efl Canvas
+    Eo* img = (Eo*) effect;
+    evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT);
+}
+
+void
+win_del(void *data, Evas_Object *o, void *ev)
+{
+    elm_exit();
+}
+
+int main(int argc, char **argv)
+{
+    //Initialize TizenVG Engine
+    tvg::Engine::init();
+
+    tvgtest();
+
+    //Show the result using EFL...
+    elm_init(argc, argv);
+
+    Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test");
+    evas_object_smart_callback_add(win, "delete,request", win_del, 0);
+
+    Eo* img = evas_object_image_filled_add(evas_object_evas_get(win));
+    evas_object_image_size_set(img, WIDTH, HEIGHT);
+    evas_object_image_data_set(img, buffer);
+    evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+    evas_object_show(img);
+
+    elm_win_resize_object_add(win, img);
+    evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT);
+    evas_object_show(win);
+
+    Elm_Transit *transit = elm_transit_add();
+    elm_transit_effect_add(transit, transit_cb, img, nullptr);
+    elm_transit_duration_set(transit, 2);
+    elm_transit_repeat_times_set(transit, -1);
+    elm_transit_go(transit);
+
+    elm_run();
+    elm_shutdown();
+
+    //Terminate TizenVG Engine
+    tvg::Engine::term();
+}