From: Hermet Park Date: Sat, 2 May 2020 17:02:43 +0000 (+0900) Subject: common shape: revise scale/rotate approach. X-Git-Tag: accepted/tizen/unified/20200806.062539~156 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=682bc252987ac42059c089f3a6ec0b3da26f86a0;p=platform%2Fcore%2Fgraphics%2Ftizenvg.git common shape: revise scale/rotate approach. 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 --- diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 8325440..93e13fc 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -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 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 gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 4e0aa51..0b1a9c7 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, UpdateFlag flags) +void* GlRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index a508eed..e9e5abe 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, 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; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4d654c9..00ff315 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -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); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index eda12cc..c9df96f 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, UpdateFlag flags) +void* SwRenderer::prepare(const Shape& shape, void* data, RenderUpdateFlag flags) { //prepare shape data SwShape* sdata = static_cast(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(surface.w), static_cast(surface.h)}; if (!shapeGenRle(shape, *sdata, clip)) return sdata; + shapeDelOutline(*sdata); } return sdata; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index ce87fa9..b299d70 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, 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); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 5a1c6c3..03be175 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -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(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}; + 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); diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 5d61991..9e8662b 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -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; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index bf937a2..0be6f4d 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -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 diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 9c41c08..17e3a27 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -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(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_ diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 9c42829..9dafdf9 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -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_ diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 1888de4..9a6152c 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -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)