common shape: revise scale/rotate approach. 66/232366/8
authorHermet Park <chuneon.park@samsung.com>
Sat, 2 May 2020 17:02:43 +0000 (02:02 +0900)
committerHermet Park <chuneon.park@samsung.com>
Sun, 3 May 2020 06:03:29 +0000 (15:03 +0900)
Come to think of it, this optimized method is not so useful,
it could just bring the user misunderstanding and
not to efficient as I expected in the most cases.

So, changed policy for transformation behaviors.
it keeps the properties as others but leaves it to the backend implementation.

Plus, this change contains the correct RenderUpdateFlag.
You can refer the flag in the backend to figure out which kinds of properites has been updated

Change-Id: Ibe0494712598a8161950b9ae2e22ac45bed1c47b

12 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/tvgShapePath.h
test/testDirectUpdate.cpp

index 8325440..93e13fc 100644 (file)
@@ -79,6 +79,8 @@ public:
     virtual int scale(float factor) = 0;
 
     virtual int bounds(float&x, float& y, float& w, float& h) const = 0;
+    virtual float scale() const = 0;
+    virtual float rotate() const = 0;
 };
 
 
@@ -139,10 +141,12 @@ public:
     int rotate(float degree) noexcept override;
     int scale(float factor) noexcept override;
 
-    int pathCommands(const PathCommand** cmds) const noexcept;
-    int pathCoords(const Point** pts) const noexcept;
+    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;
 
@@ -173,6 +177,8 @@ public:
     int scale(float factor) 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 4e0aa51..0b1a9c7 100644 (file)
@@ -65,7 +65,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data)
 }
 
 
-void* GlRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags)
+void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags)
 {
     //prepare shape data
     GlShape* sdata = static_cast<GlShape*>(data);
index a508eed..e9e5abe 100644 (file)
@@ -23,7 +23,7 @@ namespace tvg
 class GlRenderer : public RenderMethod
 {
 public:
-    void* prepare(const Shape& shape, void* data, UpdateFlag flags) override;
+    void* prepare(const Shape& shape, void* data, RenderUpdateFlag flags) override;
     bool dispose(const Shape& shape, void *data) override;
     bool render(const Shape& shape, void *data) override;
     bool clear() override;
index 4d654c9..00ff315 100644 (file)
@@ -94,7 +94,7 @@ struct SwShape
 
 void shapeReset(SwShape& sdata);
 bool shapeGenOutline(const Shape& shape, SwShape& sdata);
-void shapeDelOutline(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);
 SwRleData* rleRender(const SwShape& sdata, const SwSize& clip);
index eda12cc..c9df96f 100644 (file)
@@ -81,7 +81,7 @@ bool SwRenderer::dispose(const Shape& shape, void *data)
     return true;
 }
 
-void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags)
+void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags)
 {
     //prepare shape data
     SwShape* sdata = static_cast<SwShape*>(data);
@@ -90,7 +90,7 @@ void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags)
         assert(sdata);
     }
 
-    if (flags == UpdateFlag::None) return nullptr;
+    if (flags == RenderUpdateFlag::None) return sdata;
 
     //invisible?
     size_t alpha;
@@ -98,13 +98,14 @@ void* SwRenderer::prepare(const Shape& shape, void* data, UpdateFlag flags)
     if (alpha == 0) return sdata;
 
     //TODO: Threading
-    if (flags & UpdateFlag::Path) {
+    if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) {
         shapeReset(*sdata);
         if (!shapeGenOutline(shape, *sdata)) return sdata;
         if (!shapeTransformOutline(shape, *sdata)) return sdata;
 
         SwSize clip = {static_cast<SwCoord>(surface.w), static_cast<SwCoord>(surface.h)};
         if (!shapeGenRle(shape, *sdata, clip)) return sdata;
+        shapeDelOutline(*sdata);
     }
 
     return sdata;
index ce87fa9..b299d70 100644 (file)
@@ -22,7 +22,7 @@ class SwRenderer : public RenderMethod
 public:
     Surface surface;
 
-    void* prepare(const Shape& shape, void* data, UpdateFlag flags) override;
+    void* prepare(const Shape& shape, void* data, 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 5a1c6c3..03be175 100644 (file)
@@ -211,26 +211,57 @@ void _deleteRle(SwShape& sdata)
 }
 
 
-void _deleteOutline(SwShape& sdata)
-{
-    if (!sdata.outline) return;
-
-    SwOutline* outline = sdata.outline;
-    if (outline->cntrs) free(outline->cntrs);
-    if (outline->pts) free(outline->pts);
-    if (outline->types) free(outline->types);
-    free(outline);
-
-    sdata.outline = nullptr;
-}
-
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
 
 bool shapeTransformOutline(const Shape& shape, SwShape& sdata)
 {
-    //TODO:
+    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};
+        outline->pts[i] = TO_SWPOINT(&pt);
+    }
+
     return true;
 }
 
@@ -246,7 +277,6 @@ bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
         (sdata.bbox.min.y + sdata.bbox.max.y < 0)) goto end;
 
     sdata.rle = rleRender(sdata, clip);
-    _deleteOutline(sdata);
 
 end:
     if (sdata.rle) return true;
@@ -254,9 +284,23 @@ end:
 }
 
 
+void shapeDelOutline(SwShape& sdata)
+{
+    if (!sdata.outline) return;
+
+    SwOutline* outline = sdata.outline;
+    if (outline->cntrs) free(outline->cntrs);
+    if (outline->pts) free(outline->pts);
+    if (outline->types) free(outline->types);
+    free(outline);
+
+    sdata.outline = nullptr;
+}
+
+
 void shapeReset(SwShape& sdata)
 {
-    _deleteOutline(sdata);
+    shapeDelOutline(sdata);
     _deleteRle(sdata);
     _initBBox(sdata);
 }
@@ -277,7 +321,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata)
     auto outlinePtsCnt = 0;
     auto outlineCntrsCnt = 0;
 
-    for (auto i = 0; i < cmdCnt; ++i) {
+    for (size_t i = 0; i < cmdCnt; ++i) {
         switch(*(cmds + i)) {
             case PathCommand::Close: {
                 ++outlinePtsCnt;
@@ -311,7 +355,6 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata)
         cout << "Outline was already allocated? How?" << endl;
     }
 
-    //TODO: Probabry we can copy pts from shape directly.
     _growOutlinePoint(*outline, outlinePtsCnt);
     _growOutlineContour(*outline, outlineCntrsCnt);
 
index 5d61991..9e8662b 100644 (file)
@@ -28,12 +28,13 @@ struct Surface
     size_t w, h;
 };
 
+enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Transform = 4, All = 8};
+
 class RenderMethod
 {
 public:
-    enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 };
     virtual ~RenderMethod() {}
-    virtual void* prepare(const Shape& shape, void* data, UpdateFlag flags) = 0;
+    virtual void* prepare(const Shape& shape, void* data, 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 bf937a2..0be6f4d 100644 (file)
@@ -82,4 +82,16 @@ 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 9c41c08..17e3a27 100644 (file)
@@ -44,6 +44,7 @@ struct Shape::Impl
     float scale = 1;
     float rotate = 0;
     void *edata = nullptr;              //engine data
+    size_t flag = RenderUpdateFlag::None;
 
     Impl() : path(new ShapePath)
     {
@@ -55,14 +56,6 @@ struct Shape::Impl
         if (stroke) delete(stroke);
         if (fill) delete(fill);
     }
-
-    bool update()
-    {
-        if (path->scale(scale)) scale = 1;
-        if (path->rotate(rotate)) rotate = 0;
-
-        return true;
-    }
 };
 
 
@@ -99,10 +92,10 @@ int Shape::update(RenderMethod* engine) noexcept
     auto impl = pImpl.get();
     assert(impl);
 
-    if (!impl->update()) return -1;
-    impl->edata = engine->prepare(*this, impl->edata, RenderMethod::UpdateFlag::All);
+    impl->edata = engine->prepare(*this, impl->edata, static_cast<RenderUpdateFlag>(impl->flag));
+    impl->flag = RenderUpdateFlag::None;
     if (impl->edata) return 0;
-    return - 1;
+    return -1;
 }
 
 
@@ -113,11 +106,13 @@ int Shape::reset() noexcept
 
     impl->path->reset();
 
+    impl->flag |= RenderUpdateFlag::Path;
+
     return 0;
 }
 
 
-int Shape::pathCommands(const PathCommand** cmds) const noexcept
+size_t Shape::pathCommands(const PathCommand** cmds) const noexcept
 {
     auto impl = pImpl.get();
     assert(impl && impl->path && cmds);
@@ -128,7 +123,7 @@ int Shape::pathCommands(const PathCommand** cmds) const noexcept
 }
 
 
-int Shape::pathCoords(const Point** pts) const noexcept
+size_t Shape::pathCoords(const Point** pts) const noexcept
 {
     auto impl = pImpl.get();
     assert(impl && impl->path && pts);
@@ -150,6 +145,8 @@ int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts,
     impl->path->grow(cmdCnt, ptsCnt);
     impl->path->append(cmds, cmdCnt, pts, ptsCnt);
 
+    impl->flag |= RenderUpdateFlag::Path;
+
     return 0;
 }
 
@@ -161,6 +158,8 @@ int Shape::moveTo(float x, float y) noexcept
 
     impl->path->moveTo(x, y);
 
+    impl->flag |= RenderUpdateFlag::Path;
+
     return 0;
 }
 
@@ -172,6 +171,8 @@ int Shape::lineTo(float x, float y) noexcept
 
     impl->path->lineTo(x, y);
 
+    impl->flag |= RenderUpdateFlag::Path;
+
     return 0;
 }
 
@@ -183,6 +184,8 @@ int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
 
     impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y);
 
+    impl->flag |= RenderUpdateFlag::Path;
+
     return 0;
 }
 
@@ -194,6 +197,8 @@ int Shape::close() noexcept
 
     impl->path->close();
 
+    impl->flag |= RenderUpdateFlag::Path;
+
     return 0;
 }
 
@@ -214,6 +219,8 @@ int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexce
     impl->path->cubicTo(cx - radiusW, cy - halfKappaH, cx - halfKappaW, cy - radiusH, cx, cy - radiusH);
     impl->path->close();
 
+    impl->flag |= RenderUpdateFlag::Path;
+
     return 0;
 }
 
@@ -253,6 +260,8 @@ int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) no
         impl->path->close();
     }
 
+    impl->flag |= RenderUpdateFlag::Path;
+
     return 0;
 }
 
@@ -266,6 +275,7 @@ int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept
     impl->color[1] = g;
     impl->color[2] = b;
     impl->color[3] = a;
+    impl->flag |= RenderUpdateFlag::Fill;
 
     return 0;
 }
@@ -287,12 +297,13 @@ int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept
 
 int Shape::scale(float factor) noexcept
 {
-    if (factor < FLT_EPSILON || fabsf(factor - 1) <= FLT_EPSILON) return -1;
-
     auto impl = pImpl.get();
     assert(impl);
 
-    impl->scale *= factor;
+    if (fabsf(factor) < FLT_EPSILON || fabsf(factor - impl->scale) <= FLT_EPSILON) return -1;
+
+    impl->scale = factor;
+    impl->flag |= RenderUpdateFlag::Transform;
 
     return 0;
 }
@@ -300,12 +311,13 @@ int Shape::scale(float factor) noexcept
 
 int Shape::rotate(float degree) noexcept
 {
-    if (fabsf(degree) <= FLT_EPSILON) return -1;
-
     auto impl = pImpl.get();
     assert(impl);
 
-    impl->rotate += degree;
+    if (fabsf(degree - impl->rotate) <= FLT_EPSILON) return -1;
+
+    impl->rotate = degree;
+    impl->flag |= RenderUpdateFlag::Transform;
 
     return 0;
 }
@@ -321,4 +333,22 @@ int Shape::bounds(float& x, float& y, float& w, float& h) const noexcept
     return 0;
 }
 
+
+float Shape::scale() const noexcept
+{
+    auto impl = pImpl.get();
+    assert(impl);
+
+    return impl->scale;
+}
+
+
+float Shape::rotate() const noexcept
+{
+    auto impl = pImpl.get();
+    assert(impl);
+
+    return impl->rotate;
+}
+
 #endif //_TVG_SHAPE_CPP_
index 9c42829..9dafdf9 100644 (file)
@@ -134,49 +134,6 @@ struct ShapePath
 
         return true;
     }
-
-    bool rotate(float degree)
-    {
-        constexpr auto PI = 3.141592f;
-
-        if (fabsf(degree) <= FLT_EPSILON) return false;
-
-        float x, y, w, h;
-        if (!bounds(x, y, w, h)) return false;
-
-        auto radian = degree / 180.0f * PI;
-        auto cx = x + w * 0.5f;
-        auto cy = y + h * 0.5f;
-        auto cosVal = cosf(radian);
-        auto sinVal = sinf(radian);
-
-        for(size_t i = 0; i < ptsCnt; ++i) {
-            auto dx = pts[i].x - cx;
-            auto dy = pts[i].y - cy;
-            pts[i].x = (cosVal * dx - sinVal * dy) + cx;
-            pts[i].y = (sinVal * dx + cosVal * dy) + cy;
-        }
-
-        return true;
-    }
-
-    bool scale(float factor)
-    {
-        if (fabsf(factor - 1) <= FLT_EPSILON) return false;
-
-        float x, y, w, h;
-        if (!bounds(x, y, w, h)) return false;
-
-        auto cx = x + w * 0.5f;
-        auto cy = y + h * 0.5f;
-
-        for(size_t i = 0; i < ptsCnt; ++i) {
-            pts[i].x = (pts[i].x - cx) * factor + cx;
-            pts[i].y = (pts[i].y - cy) * factor + cy;
-        }
-
-        return true;
-    }
 };
 
 #endif //_TVG_SHAPE_PATH_CPP_
index 1888de4..9a6152c 100644 (file)
@@ -24,6 +24,8 @@ void tvgtest()
     pShape = shape.get();
 
     shape->appendRect(-100, -100, 200, 200, 0);
+
+    //fill and rotate properties will be retained
     shape->fill(127, 255, 255, 255);
     shape->rotate(45);
     canvas->push(move(shape));
@@ -42,11 +44,6 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres
     pShape->reset();    //reset path
 
     pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress));
-
-    /* rotate, scale won't be retained, when you call reset() for the shape, these values will be reset as well.
-       These are working in fire & forget method, it actually modify the path data for avoiding compuatation every frames.
-       Thus user needs to keep the last values to understand the final accumulated values. */
-    pShape->rotate(45);
     pShape->scale(1 - 0.75 * progress);
 
     //Update shape for drawing (this may work asynchronously)