diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index be78d223..aca756fd 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -19,12 +19,226 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include +#include #include "tvgPaint.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +static inline bool FLT_SAME(float a, float b) +{ + return (fabsf(a - b) < FLT_EPSILON); +} + +static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) +{ + /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ + auto shape = static_cast(cmpTarget); + + //Rectangle Candidates? + const Point* pts; + if (shape->pathCoords(&pts) != 4) return false; + + if (rTransform) rTransform->update(); + + //No Rotation? + if (pTransform && (pTransform->m.e12 != 0 || pTransform->m.e21 != 0 || pTransform->m.e11 != pTransform->m.e22)) return false; + if (rTransform && (rTransform->m.e12 != 0 || rTransform->m.e21 != 0 || rTransform->m.e11 != rTransform->m.e22)) return false; + + //Othogonal Rectangle? + auto pt1 = pts + 0; + auto pt2 = pts + 1; + auto pt3 = pts + 2; + auto pt4 = pts + 3; + + if ((FLT_SAME(pt1->x, pt2->x) && FLT_SAME(pt2->y, pt3->y) && FLT_SAME(pt3->x, pt4->x) && FLT_SAME(pt1->y, pt4->y)) || + (FLT_SAME(pt2->x, pt3->x) && FLT_SAME(pt1->y, pt2->y) && FLT_SAME(pt1->x, pt4->x) && FLT_SAME(pt3->y, pt4->y))) { + + auto x1 = pt1->x; + auto y1 = pt1->y; + auto x2 = pt3->x; + auto y2 = pt3->y; + + if (rTransform) { + x1 = x1 * rTransform->m.e11 + rTransform->m.e13; + y1 = y1 * rTransform->m.e22 + rTransform->m.e23; + x2 = x2 * rTransform->m.e11 + rTransform->m.e13; + y2 = y2 * rTransform->m.e22 + rTransform->m.e23; + } + + if (pTransform) { + x1 = x1 * pTransform->m.e11 + pTransform->m.e13; + y1 = y1 * pTransform->m.e22 + pTransform->m.e23; + x2 = x2 * pTransform->m.e11 + pTransform->m.e13; + y2 = y2 * pTransform->m.e22 + pTransform->m.e23; + } + + viewport.x = static_cast(x1); + viewport.y = static_cast(y1); + viewport.w = static_cast(roundf(x2 - x1 + 0.5f)); + viewport.h = static_cast(roundf(y2 - y1 + 0.5f)); + + return true; + } + + return false; +} + + +Paint* Paint::Impl::duplicate() +{ + auto ret = smethod->duplicate(); + if (!ret) return nullptr; + + //duplicate Transform + if (rTransform) { + ret->pImpl->rTransform = new RenderTransform(); + if (ret->pImpl->rTransform) { + *ret->pImpl->rTransform = *rTransform; + ret->pImpl->flag |= RenderUpdateFlag::Transform; + } + } + + ret->pImpl->opacity = opacity; + + if (cmpTarget) ret->pImpl->cmpTarget = cmpTarget->duplicate(); + + ret->pImpl->cmpMethod = cmpMethod; + + return ret; +} + + +bool Paint::Impl::rotate(float degree) +{ + if (rTransform) { + if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; + } else { + if (fabsf(degree) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->degree = degree; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; +} + + +bool Paint::Impl::scale(float factor) +{ + if (rTransform) { + if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; + } else { + if (fabsf(factor) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->scale = factor; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; +} + + +bool Paint::Impl::translate(float x, float y) +{ + if (rTransform) { + if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; + } else { + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->x = x; + rTransform->y = y; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; +} + + +bool Paint::Impl::render(RenderMethod& renderer) +{ + Compositor* cmp = nullptr; + + /* Note: only ClipPath is processed in update() step. + Create a composition image. */ + if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) { + auto region = cmpTarget->pImpl->bounds(renderer); + if (region.w == 0 || region.h == 0) return false; + cmp = renderer.target(region); + renderer.beginComposite(cmp, CompositeMethod::None, 255); + cmpTarget->pImpl->render(renderer); + } + + if (cmp) renderer.beginComposite(cmp, cmpMethod, cmpTarget->pImpl->opacity); + + auto ret = smethod->render(renderer); + + if (cmp) renderer.endComposite(cmp); + + return ret; +} + + +void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag) +{ + if (flag & RenderUpdateFlag::Transform) { + if (!rTransform) return nullptr; + if (!rTransform->update()) { + delete(rTransform); + rTransform = nullptr; + } + } + + /* 1. Composition Pre Processing */ + void *cmpData = nullptr; + RenderRegion viewport; + bool cmpFastTrack = false; + + if (cmpTarget) { + /* If transform has no rotation factors && ClipPath is a simple rectangle, + we can avoid regular ClipPath sequence but use viewport for performance */ + if (cmpMethod == CompositeMethod::ClipPath) { + RenderRegion viewport2; + if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, cmpTarget->pImpl->rTransform, viewport2))) { + viewport = renderer.viewport(); + viewport2.merge(viewport); + renderer.viewport(viewport2); + } + } + + if (!cmpFastTrack) { + cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag); + if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData); + } + } + + /* 2. Main Update */ + void *edata = nullptr; + auto newFlag = static_cast(pFlag | flag); + flag = RenderUpdateFlag::None; + opacity = (opacity * this->opacity) / 255; + + if (rTransform && pTransform) { + RenderTransform outTransform(pTransform, rTransform); + edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag); + } else { + auto outTransform = pTransform ? pTransform : rTransform; + edata = smethod->update(renderer, outTransform, opacity, clips, newFlag); + } + + /* 3. Composition Post Processing */ + if (cmpFastTrack) renderer.viewport(viewport); + else if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop(); + + return edata; +} + + Paint :: Paint() : pImpl(new Impl()) { } diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 2df21c73..044c3aa1 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -22,69 +22,8 @@ #ifndef _TVG_PAINT_H_ #define _TVG_PAINT_H_ -#include -#include #include "tvgRender.h" -static inline bool FLT_SAME(float a, float b) -{ - return (fabsf(a - b) < FLT_EPSILON); -} - -static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) -{ - /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ - auto shape = static_cast(cmpTarget); - - //Rectangle Candidates? - const Point* pts; - if (shape->pathCoords(&pts) != 4) return false; - - if (rTransform) rTransform->update(); - - //No Rotation? - if (pTransform && (pTransform->m.e12 != 0 || pTransform->m.e21 != 0 || pTransform->m.e11 != pTransform->m.e22)) return false; - if (rTransform && (rTransform->m.e12 != 0 || rTransform->m.e21 != 0 || rTransform->m.e11 != rTransform->m.e22)) return false; - - //Othogonal Rectangle? - auto pt1 = pts + 0; - auto pt2 = pts + 1; - auto pt3 = pts + 2; - auto pt4 = pts + 3; - - if ((FLT_SAME(pt1->x, pt2->x) && FLT_SAME(pt2->y, pt3->y) && FLT_SAME(pt3->x, pt4->x) && FLT_SAME(pt1->y, pt4->y)) || - (FLT_SAME(pt2->x, pt3->x) && FLT_SAME(pt1->y, pt2->y) && FLT_SAME(pt1->x, pt4->x) && FLT_SAME(pt3->y, pt4->y))) { - - auto x1 = pt1->x; - auto y1 = pt1->y; - auto x2 = pt3->x; - auto y2 = pt3->y; - - if (rTransform) { - x1 = x1 * rTransform->m.e11 + rTransform->m.e13; - y1 = y1 * rTransform->m.e22 + rTransform->m.e23; - x2 = x2 * rTransform->m.e11 + rTransform->m.e13; - y2 = y2 * rTransform->m.e22 + rTransform->m.e23; - } - - if (pTransform) { - x1 = x1 * pTransform->m.e11 + pTransform->m.e13; - y1 = y1 * pTransform->m.e22 + pTransform->m.e23; - x2 = x2 * pTransform->m.e11 + pTransform->m.e13; - y2 = y2 * pTransform->m.e22 + pTransform->m.e23; - } - - viewport.x = static_cast(x1); - viewport.y = static_cast(y1); - viewport.w = static_cast(roundf(x2 - x1 + 0.5f)); - viewport.h = static_cast(roundf(y2 - y1 + 0.5f)); - - return true; - } - - return false; -} - namespace tvg { @@ -107,12 +46,9 @@ namespace tvg StrategyMethod* smethod = nullptr; RenderTransform *rTransform = nullptr; uint32_t flag = RenderUpdateFlag::None; - Paint* cmpTarget = nullptr; CompositeMethod cmpMethod = CompositeMethod::None; - uint8_t opacity = 255; - PaintType type; ~Impl() { @@ -126,52 +62,6 @@ namespace tvg smethod = method; } - bool rotate(float degree) - { - if (rTransform) { - if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; - } else { - if (fabsf(degree) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->degree = degree; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool scale(float factor) - { - if (rTransform) { - if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; - } else { - if (fabsf(factor) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->scale = factor; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool translate(float x, float y) - { - if (rTransform) { - if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; - } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->x = x; - rTransform->y = y; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - bool transform(const Matrix& m) { if (!rTransform) { @@ -200,106 +90,6 @@ namespace tvg return smethod->dispose(renderer); } - void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag) - { - if (flag & RenderUpdateFlag::Transform) { - if (!rTransform) return nullptr; - if (!rTransform->update()) { - delete(rTransform); - rTransform = nullptr; - } - } - - /* 1. Composition Pre Processing */ - void *cmpData = nullptr; - RenderRegion viewport; - bool cmpFastTrack = false; - - if (cmpTarget) { - /* If transform has no rotation factors && ClipPath is a simple rectangle, - we can avoid regular ClipPath sequence but use viewport for performance */ - if (cmpMethod == CompositeMethod::ClipPath) { - RenderRegion viewport2; - if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, cmpTarget->pImpl->rTransform, viewport2))) { - viewport = renderer.viewport(); - viewport2.merge(viewport); - renderer.viewport(viewport2); - } - } - - if (!cmpFastTrack) { - cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag); - if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData); - } - } - - /* 2. Main Update */ - void *edata = nullptr; - auto newFlag = static_cast(pFlag | flag); - flag = RenderUpdateFlag::None; - opacity = (opacity * this->opacity) / 255; - - if (rTransform && pTransform) { - RenderTransform outTransform(pTransform, rTransform); - edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag); - } else { - auto outTransform = pTransform ? pTransform : rTransform; - edata = smethod->update(renderer, outTransform, opacity, clips, newFlag); - } - - /* 3. Composition Post Processing */ - if (cmpFastTrack) renderer.viewport(viewport); - else if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop(); - - return edata; - } - - bool render(RenderMethod& renderer) - { - Compositor* cmp = nullptr; - - /* Note: only ClipPath is processed in update() step. - Create a composition image. */ - if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) { - auto region = cmpTarget->pImpl->bounds(renderer); - if (region.w == 0 || region.h == 0) return false; - cmp = renderer.target(region); - renderer.beginComposite(cmp, CompositeMethod::None, 255); - cmpTarget->pImpl->render(renderer); - } - - if (cmp) renderer.beginComposite(cmp, cmpMethod, cmpTarget->pImpl->opacity); - - auto ret = smethod->render(renderer); - - if (cmp) renderer.endComposite(cmp); - - return ret; - } - - Paint* duplicate() - { - auto ret = smethod->duplicate(); - if (!ret) return nullptr; - - //duplicate Transform - if (rTransform) { - ret->pImpl->rTransform = new RenderTransform(); - if (ret->pImpl->rTransform) { - *ret->pImpl->rTransform = *rTransform; - ret->pImpl->flag |= RenderUpdateFlag::Transform; - } - } - - ret->pImpl->opacity = opacity; - - if (cmpTarget) ret->pImpl->cmpTarget = cmpTarget->duplicate(); - - ret->pImpl->cmpMethod = cmpMethod; - - return ret; - } - bool composite(Paint* target, CompositeMethod method) { if ((!target && method != CompositeMethod::None) || (target && method == CompositeMethod::None)) return false; @@ -308,6 +98,13 @@ namespace tvg cmpMethod = method; return true; } + + bool rotate(float degree); + bool scale(float factor); + bool translate(float x, float y); + void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag); + bool render(RenderMethod& renderer); + Paint* duplicate(); }; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index b32c0368..40f1e58f 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -22,6 +22,7 @@ #ifndef _TVG_SCENE_IMPL_H_ #define _TVG_SCENE_IMPL_H_ +#include #include "tvgPaint.h" /************************************************************************/ diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 0b1f870b..68013ce9 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -20,6 +20,8 @@ * SOFTWARE. */ #include +#include +#include #include "tvgShapeImpl.h" /************************************************************************/