diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 83254406..93e13fc2 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 4e0aa518..0b1a9c73 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 a508eed6..e9e5abe8 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 4d654c93..00ff3156 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 eda12cc1..c9df96f7 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 ce87fa9c..b299d70a 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 5a1c6c3d..03be175d 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 5d619913..9e8662bf 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 bf937a24..0be6f4d7 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 9c41c082..17e3a274 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 9c42829c..9dafdf92 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 1888de44..9a6152c6 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)