From 1806b329718589a36b606cac5760e41dacb586f6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 13 Dec 2024 17:31:58 +0900 Subject: [PATCH] common: optimization pImpl data structures ThorVG pImpl idiom caused internal data to be scattered across hierarchical classes. This refactoring consolidates the data by inheriting pImpl internally, reducing memory allocation counts and eliminating unnecessary strategy methods. --- inc/thorvg.h | 33 ++-- src/loaders/external_jpg/tvgJpgLoader.cpp | 1 - src/loaders/external_png/tvgPngLoader.cpp | 1 - src/loaders/external_webp/tvgWebpLoader.cpp | 1 - src/loaders/lottie/thorvg_lottie.h | 4 +- src/loaders/lottie/tvgLottieAnimation.cpp | 20 +-- src/loaders/lottie/tvgLottieBuilder.cpp | 76 ++++----- src/loaders/lottie/tvgLottieBuilder.h | 2 +- src/loaders/png/tvgPngLoader.cpp | 1 - src/loaders/raw/tvgRawLoader.cpp | 8 - src/loaders/svg/tvgSvgPath.cpp | 4 +- src/loaders/svg/tvgSvgSceneBuilder.cpp | 4 +- src/loaders/ttf/tvgTtfReader.cpp | 4 +- src/renderer/gl_engine/tvgGlGeometry.cpp | 17 +- src/renderer/gl_engine/tvgGlGpuBuffer.cpp | 49 ++++-- src/renderer/gl_engine/tvgGlGpuBuffer.h | 10 +- src/renderer/gl_engine/tvgGlProgram.cpp | 74 ++++---- src/renderer/gl_engine/tvgGlRenderTask.cpp | 3 - src/renderer/gl_engine/tvgGlRenderer.cpp | 2 - src/renderer/gl_engine/tvgGlShader.cpp | 56 ++++--- src/renderer/gl_engine/tvgGlTessellator.h | 3 +- src/renderer/sw_engine/tvgSwFill.cpp | 32 ++-- src/renderer/sw_engine/tvgSwRaster.cpp | 1 + src/renderer/tvgAnimation.cpp | 19 +-- src/renderer/tvgCanvas.cpp | 6 +- src/renderer/tvgCanvas.h | 9 +- src/renderer/tvgCommon.h | 5 +- src/renderer/tvgFill.cpp | 121 ++------------ src/renderer/tvgFill.h | 143 +++++++++++----- src/renderer/tvgGlCanvas.cpp | 36 +--- src/renderer/tvgIteratorAccessor.h | 2 +- src/renderer/tvgPaint.cpp | 121 +++----------- src/renderer/tvgPaint.h | 109 +++++++++++- src/renderer/tvgPicture.cpp | 139 +--------------- src/renderer/tvgPicture.h | 163 ++++++++++++++---- src/renderer/tvgRender.cpp | 8 - src/renderer/tvgScene.cpp | 69 +------- src/renderer/tvgScene.h | 74 ++++++-- src/renderer/tvgShape.cpp | 176 ++++---------------- src/renderer/tvgShape.h | 172 ++++++++++++++----- src/renderer/tvgSwCanvas.cpp | 39 ++--- src/renderer/tvgText.cpp | 28 +--- src/renderer/tvgText.h | 48 +++--- src/renderer/tvgWgCanvas.cpp | 30 +--- src/renderer/wg_engine/tvgWgBindGroups.h | 4 +- src/renderer/wg_engine/tvgWgCompositor.h | 45 ++--- src/renderer/wg_engine/tvgWgPipelines.h | 3 +- 47 files changed, 895 insertions(+), 1080 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index aeb8a1b2..fed62b7a 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -43,12 +43,16 @@ #define _TVG_DECLARE_PRIVATE(A) \ struct Impl; \ - Impl* pImpl; \ protected: \ A(const A&) = delete; \ const A& operator=(const A&) = delete; \ A() +#define _TVG_DECLARE_PRIVATE_BASE(A) \ + _TVG_DECLARE_PRIVATE(A); \ +public: \ + Impl* pImpl + #define _TVG_DISABLE_CTOR(A) \ A() = delete; \ ~A() = delete @@ -515,7 +519,7 @@ public: */ uint32_t id = 0; - _TVG_DECLARE_PRIVATE(Paint); + _TVG_DECLARE_PRIVATE_BASE(Paint); }; @@ -616,7 +620,7 @@ public: */ virtual Type type() const noexcept = 0; - _TVG_DECLARE_PRIVATE(Fill); + _TVG_DECLARE_PRIVATE_BASE(Fill); }; @@ -633,7 +637,6 @@ public: class TVG_API Canvas { public: - Canvas(RenderMethod*); virtual ~Canvas(); /** @@ -749,7 +752,7 @@ public: */ Result sync() noexcept; - _TVG_DECLARE_PRIVATE(Canvas); + _TVG_DECLARE_PRIVATE_BASE(Canvas); }; @@ -764,8 +767,6 @@ public: class TVG_API LinearGradient final : public Fill { public: - ~LinearGradient(); - /** * @brief Sets the linear gradient bounds. * @@ -828,8 +829,6 @@ public: class TVG_API RadialGradient final : public Fill { public: - ~RadialGradient(); - /** * @brief Sets the radial gradient attributes. * @@ -906,8 +905,6 @@ public: class TVG_API Shape final : public Paint { public: - ~Shape(); - /** * @brief Resets the shape path. * @@ -1287,8 +1284,6 @@ public: class TVG_API Picture final : public Paint { public: - ~Picture(); - /** * @brief Loads a picture data directly from a file. * @@ -1420,8 +1415,6 @@ public: class TVG_API Scene final : public Paint { public: - ~Scene(); - /** * @brief Inserts a paint object to the scene. * @@ -1519,8 +1512,6 @@ public: class TVG_API Text final : public Paint { public: - ~Text(); - /** * @brief Sets the font properties for the text. * @@ -1902,7 +1893,7 @@ public: class TVG_API Animation { public: - ~Animation(); + virtual ~Animation(); /** * @brief Specifies the current frame in the animation. @@ -2012,7 +2003,7 @@ public: */ static Animation* gen() noexcept; - _TVG_DECLARE_PRIVATE(Animation); + _TVG_DECLARE_PRIVATE_BASE(Animation); }; @@ -2115,7 +2106,7 @@ public: */ static Saver* gen() noexcept; - _TVG_DECLARE_PRIVATE(Saver); + _TVG_DECLARE_PRIVATE_BASE(Saver); }; @@ -2171,7 +2162,7 @@ public: */ static Accessor* gen() noexcept; - _TVG_DECLARE_PRIVATE(Accessor); + _TVG_DECLARE_PRIVATE_BASE(Accessor); }; /** @}*/ diff --git a/src/loaders/external_jpg/tvgJpgLoader.cpp b/src/loaders/external_jpg/tvgJpgLoader.cpp index 9b8a7ca0..55051138 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.cpp +++ b/src/loaders/external_jpg/tvgJpgLoader.cpp @@ -36,7 +36,6 @@ void JpgLoader::clear() freeData = false; } - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ diff --git a/src/loaders/external_png/tvgPngLoader.cpp b/src/loaders/external_png/tvgPngLoader.cpp index 1f64a0c7..192d709d 100644 --- a/src/loaders/external_png/tvgPngLoader.cpp +++ b/src/loaders/external_png/tvgPngLoader.cpp @@ -33,7 +33,6 @@ void PngLoader::clear() image = nullptr; } - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ diff --git a/src/loaders/external_webp/tvgWebpLoader.cpp b/src/loaders/external_webp/tvgWebpLoader.cpp index 963f105e..d417e284 100644 --- a/src/loaders/external_webp/tvgWebpLoader.cpp +++ b/src/loaders/external_webp/tvgWebpLoader.cpp @@ -30,7 +30,6 @@ /* Internal Class Implementation */ /************************************************************************/ - void WebpLoader::run(unsigned tid) { //TODO: acquire the current colorspace format & pre-multiplied alpha image. diff --git a/src/loaders/lottie/thorvg_lottie.h b/src/loaders/lottie/thorvg_lottie.h index 1518bc39..a199ec70 100644 --- a/src/loaders/lottie/thorvg_lottie.h +++ b/src/loaders/lottie/thorvg_lottie.h @@ -20,8 +20,6 @@ namespace tvg class TVG_API LottieAnimation final : public Animation { public: - ~LottieAnimation(); - /** * @brief Override Lottie properties using slot data. * @@ -87,6 +85,8 @@ public: * @since 0.15 */ static LottieAnimation* gen() noexcept; + + _TVG_DECLARE_PRIVATE(LottieAnimation); }; } //namespace diff --git a/src/loaders/lottie/tvgLottieAnimation.cpp b/src/loaders/lottie/tvgLottieAnimation.cpp index a73b52cc..668169c0 100644 --- a/src/loaders/lottie/tvgLottieAnimation.cpp +++ b/src/loaders/lottie/tvgLottieAnimation.cpp @@ -26,24 +26,16 @@ #include "tvgAnimation.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -LottieAnimation::~LottieAnimation() +LottieAnimation::LottieAnimation() { } Result LottieAnimation::override(const char* slot) noexcept { - if (!pImpl->picture->pImpl->loader) return Result::InsufficientCondition; + if (!PICTURE(pImpl->picture)->loader) return Result::InsufficientCondition; - if (static_cast(pImpl->picture->pImpl->loader)->override(slot)) return Result::Success; + if (static_cast(PICTURE(pImpl->picture)->loader)->override(slot)) return Result::Success; return Result::InvalidArguments; } @@ -51,7 +43,7 @@ Result LottieAnimation::override(const char* slot) noexcept Result LottieAnimation::segment(const char* marker) noexcept { - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return Result::InsufficientCondition; if (!marker) { @@ -68,7 +60,7 @@ Result LottieAnimation::segment(const char* marker) noexcept uint32_t LottieAnimation::markersCnt() noexcept { - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return 0; return static_cast(loader)->markersCnt(); } @@ -76,7 +68,7 @@ uint32_t LottieAnimation::markersCnt() noexcept const char* LottieAnimation::marker(uint32_t idx) noexcept { - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return nullptr; return static_cast(loader)->markers(idx); } diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index a4ee8337..1f108a79 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -189,10 +189,10 @@ void LottieBuilder::updateTransform(LottieGroup* parent, LottieObject** child, f if (!_updateTransform(transform, frameNo, false, matrix, opacity, exps)) return; ctx->propagator->transform(ctx->propagator->transform() * matrix); - ctx->propagator->opacity(MULTIPLY(opacity, PP(ctx->propagator)->opacity)); + ctx->propagator->opacity(MULTIPLY(opacity, PAINT(ctx->propagator)->opacity)); //FIXME: preserve the stroke width. too workaround, need a better design. - if (P(ctx->propagator)->rs.strokeWidth() > 0.0f) { + if (SHAPE(ctx->propagator)->rs.strokeWidth() > 0.0f) { auto denominator = sqrtf(matrix.e11 * matrix.e11 + matrix.e12 * matrix.e12); if (denominator > 1.0f) ctx->propagator->strokeWidth(ctx->propagator->strokeWidth() / denominator); } @@ -213,7 +213,7 @@ void LottieBuilder::updateGroup(LottieGroup* parent, LottieObject** child, float if (group->mergeable()) _draw(parent, nullptr, ctx); Inlist contexts; - auto propagator = group->mergeable() ? ctx->propagator : static_cast(PP(ctx->propagator)->duplicate(group->pooling())); + auto propagator = group->mergeable() ? ctx->propagator : static_cast(PAINT(ctx->propagator)->duplicate(group->pooling())); contexts.back(new RenderContext(*ctx, propagator, group->mergeable())); updateChildren(group, frameNo, contexts); @@ -243,7 +243,7 @@ static bool _fragmented(LottieGroup* parent, LottieObject** child, InlistreqFragment) return false; if (ctx->fragmenting) return true; - contexts.back(new RenderContext(*ctx, static_cast(PP(ctx->propagator)->duplicate(parent->pooling())))); + contexts.back(new RenderContext(*ctx, static_cast(PAINT(ctx->propagator)->duplicate(parent->pooling())))); auto fragment = contexts.tail; fragment->begin = child - 1; ctx->fragmenting = true; @@ -313,7 +313,7 @@ static bool _draw(LottieGroup* parent, LottieShape* shape, RenderContext* ctx) if (shape) { ctx->merging = shape->pooling(); - PP(ctx->propagator)->duplicate(ctx->merging); + PAINT(ctx->propagator)->duplicate(ctx->merging); } else { ctx->merging = static_cast(ctx->propagator->duplicate()); } @@ -338,7 +338,7 @@ static void _repeat(LottieGroup* parent, Shape* path, RenderContext* ctx) for (auto propagator = propagators.begin(); propagator < propagators.end(); ++propagator) { auto shape = static_cast((*propagator)->duplicate()); - P(shape)->rs.path = P(path)->rs.path; + SHAPE(shape)->rs.path = SHAPE(path)->rs.path; auto opacity = repeater->interpOpacity ? lerp(repeater->startOpacity, repeater->endOpacity, static_cast(i + 1) / repeater->cnt) : repeater->startOpacity; shape->opacity(opacity); @@ -405,7 +405,7 @@ static void _appendRect(Shape* shape, float x, float y, float w, float h, float } } - if (offsetPath) offsetPath->modifyRect(commands, 5, points, 4, P(shape)->rs.path.cmds, P(shape)->rs.path.pts); + if (offsetPath) offsetPath->modifyRect(commands, 5, points, 4, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts); else shape->appendPath(commands, 5, points, 4); //round rect } else { @@ -458,7 +458,7 @@ static void _appendRect(Shape* shape, float x, float y, float w, float h, float } } - if (offsetPath) offsetPath->modifyRect(commands, cmdCnt, points, ptsCnt, P(shape)->rs.path.cmds, P(shape)->rs.path.pts); + if (offsetPath) offsetPath->modifyRect(commands, cmdCnt, points, ptsCnt, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts); else shape->appendPath(commands, cmdCnt, points, ptsCnt); } } @@ -557,12 +557,12 @@ void LottieBuilder::updatePath(LottieGroup* parent, LottieObject** child, float if (!ctx->repeaters.empty()) { auto shape = path->pooling(); shape->reset(); - path->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, ctx->transform, ctx->roundness, ctx->offsetPath, exps); + path->pathset(frameNo, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, ctx->transform, ctx->roundness, ctx->offsetPath, exps); _repeat(parent, shape, ctx); } else { _draw(parent, path, ctx); - if (path->pathset(frameNo, P(ctx->merging)->rs.path.cmds, P(ctx->merging)->rs.path.pts, ctx->transform, ctx->roundness, ctx->offsetPath, exps)) { - P(ctx->merging)->update(RenderUpdateFlag::Path); + if (path->pathset(frameNo, SHAPE(ctx->merging)->rs.path.cmds, SHAPE(ctx->merging)->rs.path.pts, ctx->transform, ctx->roundness, ctx->offsetPath, exps)) { + PAINT(ctx->merging)->update(RenderUpdateFlag::Path); } } } @@ -615,11 +615,11 @@ static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Ma } if (tvg::zero(innerRoundness) && tvg::zero(outerRoundness)) { - P(shape)->rs.path.pts.reserve(numPoints + 2); - P(shape)->rs.path.cmds.reserve(numPoints + 3); + SHAPE(shape)->rs.path.pts.reserve(numPoints + 2); + SHAPE(shape)->rs.path.cmds.reserve(numPoints + 3); } else { - P(shape)->rs.path.pts.reserve(numPoints * 3 + 2); - P(shape)->rs.path.cmds.reserve(numPoints + 3); + SHAPE(shape)->rs.path.pts.reserve(numPoints * 3 + 2); + SHAPE(shape)->rs.path.cmds.reserve(numPoints + 3); hasRoundness = true; } @@ -687,13 +687,13 @@ static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Ma if (roundedCorner) { if (offsetPath) { auto intermediate = Shape::gen(); - roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, outerRoundness, hasRoundness); - offsetPath->modifyPolystar(P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts); + roundness->modifyPolystar(SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, SHAPE(intermediate)->rs.path.cmds, SHAPE(intermediate)->rs.path.pts, outerRoundness, hasRoundness); + offsetPath->modifyPolystar(SHAPE(intermediate)->rs.path.cmds, SHAPE(intermediate)->rs.path.pts, SHAPE(merging)->rs.path.cmds, SHAPE(merging)->rs.path.pts); delete(intermediate); } else { - roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, outerRoundness, hasRoundness); + roundness->modifyPolystar(SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, SHAPE(merging)->rs.path.cmds, SHAPE(merging)->rs.path.pts, outerRoundness, hasRoundness); } - } else if (offsetPath) offsetPath->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts); + } else if (offsetPath) offsetPath->modifyPolystar(SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, SHAPE(merging)->rs.path.cmds, SHAPE(merging)->rs.path.pts); } @@ -722,11 +722,11 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr } else { shape = merging; if (hasRoundness) { - P(shape)->rs.path.pts.reserve(ptsCnt * 3 + 2); - P(shape)->rs.path.cmds.reserve(ptsCnt + 3); + SHAPE(shape)->rs.path.pts.reserve(ptsCnt * 3 + 2); + SHAPE(shape)->rs.path.cmds.reserve(ptsCnt + 3); } else { - P(shape)->rs.path.pts.reserve(ptsCnt + 2); - P(shape)->rs.path.cmds.reserve(ptsCnt + 3); + SHAPE(shape)->rs.path.pts.reserve(ptsCnt + 2); + SHAPE(shape)->rs.path.cmds.reserve(ptsCnt + 3); } } @@ -774,13 +774,13 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr if (roundedCorner) { if (offsetPath) { auto intermediate = Shape::gen(); - roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, 0.0f, false); - offsetPath->modifyPolystar(P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts); + roundness->modifyPolystar(SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, SHAPE(intermediate)->rs.path.cmds, SHAPE(intermediate)->rs.path.pts, 0.0f, false); + offsetPath->modifyPolystar(SHAPE(intermediate)->rs.path.cmds, SHAPE(intermediate)->rs.path.pts, SHAPE(merging)->rs.path.cmds, SHAPE(merging)->rs.path.pts); delete(intermediate); } else { - roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, 0.0f, false); + roundness->modifyPolystar(SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, SHAPE(merging)->rs.path.cmds, SHAPE(merging)->rs.path.pts, 0.0f, false); } - } else if (offsetPath) offsetPath->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts); + } else if (offsetPath) offsetPath->modifyPolystar(SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, SHAPE(merging)->rs.path.cmds, SHAPE(merging)->rs.path.pts); } @@ -809,7 +809,7 @@ void LottieBuilder::updatePolystar(LottieGroup* parent, LottieObject** child, fl _draw(parent, star, ctx); if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offsetPath, frameNo, ctx->merging, exps); else _updatePolygon(parent, star, identity ? nullptr : &matrix, ctx->roundness, ctx->offsetPath, frameNo, ctx->merging, exps); - P(ctx->merging)->update(RenderUpdateFlag::Path); + PAINT(ctx->merging)->update(RenderUpdateFlag::Path); } } @@ -861,15 +861,15 @@ void LottieBuilder::updateTrimpath(TVG_UNUSED LottieGroup* parent, LottieObject* float begin, end; trimpath->segment(frameNo, begin, end, exps); - if (P(ctx->propagator)->rs.stroke) { - auto pbegin = P(ctx->propagator)->rs.stroke->trim.begin; - auto pend = P(ctx->propagator)->rs.stroke->trim.end; + if (SHAPE(ctx->propagator)->rs.stroke) { + auto pbegin = SHAPE(ctx->propagator)->rs.stroke->trim.begin; + auto pend = SHAPE(ctx->propagator)->rs.stroke->trim.end; auto length = fabsf(pend - pbegin); begin = (length * begin) + pbegin; end = (length * end) + pbegin; } - P(ctx->propagator)->strokeTrim(begin, end, trimpath->type == LottieTrimpath::Type::Simultaneous); + ctx->propagator->strokeTrim(begin, end, trimpath->type == LottieTrimpath::Type::Simultaneous); ctx->merging = nullptr; } @@ -1083,8 +1083,8 @@ void LottieBuilder::updateText(LottieLayer* layer, float frameNo) for (auto g = glyph->children.begin(); g < glyph->children.end(); ++g) { auto group = static_cast(*g); for (auto p = group->children.begin(); p < group->children.end(); ++p) { - if (static_cast(*p)->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, nullptr, nullptr, nullptr)) { - P(shape)->update(RenderUpdateFlag::Path); + if (static_cast(*p)->pathset(frameNo, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, nullptr, nullptr, nullptr)) { + PAINT(shape)->update(RenderUpdateFlag::Path); } } } @@ -1237,11 +1237,11 @@ void LottieBuilder::updateMaskings(LottieLayer* layer, float frameNo) //Apply Masking Expansion (Offset) if (expand == 0.0f) { - pMask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); + pMask->pathset(frameNo, SHAPE(pShape)->rs.path.cmds, SHAPE(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); } else { //TODO: Once path direction support is implemented, ensure that the direction is ignored here auto offset = LottieOffsetModifier(pMask->expand(frameNo)); - pMask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, &offset, exps); + pMask->pathset(frameNo, SHAPE(pShape)->rs.path.cmds, SHAPE(pShape)->rs.path.pts, nullptr, nullptr, &offset, exps); } auto compMethod = (pMethod == MaskMethod::Subtract || pMethod == MaskMethod::InvAlpha) ? MaskMethod::InvAlpha : MaskMethod::Alpha; @@ -1269,14 +1269,14 @@ void LottieBuilder::updateMaskings(LottieLayer* layer, float frameNo) //Append the mask shape if (pMethod == method && (method == MaskMethod::Subtract || method == MaskMethod::Difference)) { - mask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); + mask->pathset(frameNo, SHAPE(pShape)->rs.path.cmds, SHAPE(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); //Chain composition } else { auto shape = layer->pooling(); shape->reset(); shape->fill(255, 255, 255, mask->opacity(frameNo)); shape->transform(layer->cache.matrix); - mask->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, nullptr, nullptr, nullptr, exps); + mask->pathset(frameNo, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, nullptr, nullptr, nullptr, exps); pShape->mask(shape, method); pShape = shape; pMethod = method; diff --git a/src/loaders/lottie/tvgLottieBuilder.h b/src/loaders/lottie/tvgLottieBuilder.h index 17278c22..29d99653 100644 --- a/src/loaders/lottie/tvgLottieBuilder.h +++ b/src/loaders/lottie/tvgLottieBuilder.h @@ -62,7 +62,7 @@ struct RenderContext RenderContext(Shape* propagator) { - P(propagator)->reset(); + SHAPE(propagator)->reset(); propagator->ref(); this->propagator = propagator; } diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index 5d118e82..559916a0 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -29,7 +29,6 @@ /* Internal Class Implementation */ /************************************************************************/ - void PngLoader::run(unsigned tid) { auto width = static_cast(w); diff --git a/src/loaders/raw/tvgRawLoader.cpp b/src/loaders/raw/tvgRawLoader.cpp index 68048e74..d5162583 100644 --- a/src/loaders/raw/tvgRawLoader.cpp +++ b/src/loaders/raw/tvgRawLoader.cpp @@ -25,14 +25,6 @@ #include "tvgLoader.h" #include "tvgRawLoader.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ RawLoader::RawLoader() : ImageLoader(FileType::Raw) { diff --git a/src/loaders/svg/tvgSvgPath.cpp b/src/loaders/svg/tvgSvgPath.cpp index 30a5c09b..831e0a8f 100644 --- a/src/loaders/svg/tvgSvgPath.cpp +++ b/src/loaders/svg/tvgSvgPath.cpp @@ -527,8 +527,8 @@ bool svgPathToShape(const char* svgPath, Shape* shape) bool closed = false; char* path = (char*)svgPath; - auto& pts = P(shape)->rs.path.pts; - auto& cmds = P(shape)->rs.path.cmds; + auto& pts = SHAPE(shape)->rs.path.pts; + auto& cmds = SHAPE(shape)->rs.path.cmds; auto lastCmds = cmds.count; while ((path[0] != '\0')) { diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 2afe8bab..619f86dc 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -153,7 +153,7 @@ static RadialGradient* _applyRadialGradientProperty(SvgStyleGradient* g, const B else finalTransform = m; } - P(fillGrad)->radial(g->radial->cx, g->radial->cy, g->radial->r, g->radial->fx, g->radial->fy, g->radial->fr); + fillGrad->radial(g->radial->cx, g->radial->cy, g->radial->r, g->radial->fx, g->radial->fy, g->radial->fr); fillGrad->spread(g->spread); //Update the stops @@ -216,7 +216,7 @@ static Matrix _compositionTransform(Paint* paint, const SvgNode* node, const Svg } if (!compNode->node.clip.userSpace) { float x, y, w, h; - P(paint)->bounds(&x, &y, &w, &h, false, false); + PAINT(paint)->bounds(&x, &y, &w, &h, false, false); m *= {w, 0, x, 0, h, y, 0, 0, 1}; } return m; diff --git a/src/loaders/ttf/tvgTtfReader.cpp b/src/loaders/ttf/tvgTtfReader.cpp index b2f029d2..9cbea770 100644 --- a/src/loaders/ttf/tvgTtfReader.cpp +++ b/src/loaders/ttf/tvgTtfReader.cpp @@ -479,8 +479,8 @@ bool TtfReader::convert(Shape* shape, TtfGlyphMetrics& gmetrics, const Point& of if (!this->points(outline, flags, pts, ptsCnt, offset + kerning)) return false; //generate tvg paths. - auto& pathCmds = P(shape)->rs.path.cmds; - auto& pathPts = P(shape)->rs.path.pts; + auto& pathCmds = SHAPE(shape)->rs.path.cmds; + auto& pathPts = SHAPE(shape)->rs.path.pts; pathCmds.reserve(ptsCnt); pathPts.reserve(ptsCnt); diff --git a/src/renderer/gl_engine/tvgGlGeometry.cpp b/src/renderer/gl_engine/tvgGlGeometry.cpp index 92437661..213f099f 100644 --- a/src/renderer/gl_engine/tvgGlGeometry.cpp +++ b/src/renderer/gl_engine/tvgGlGeometry.cpp @@ -35,13 +35,9 @@ bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag) fillVertex.clear(); fillIndex.clear(); - BWTessellator bwTess{&fillVertex, &fillIndex}; - bwTess.tessellate(&rshape, mMatrix); - mFillRule = rshape.rule; - mBounds = bwTess.bounds(); } @@ -51,7 +47,6 @@ bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag) Stroker stroke{&strokeVertex, &strokeIndex, mMatrix}; stroke.stroke(&rshape); - mBounds = stroke.bounds(); } @@ -123,10 +118,7 @@ void GlGeometry::disableVertex(uint32_t location) bool GlGeometry::draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdateFlag flag) { - - if (flag == RenderUpdateFlag::None) { - return false; - } + if (flag == RenderUpdateFlag::None) return false; Array* vertexBuffer = nullptr; Array* indexBuffer = nullptr; @@ -220,10 +212,7 @@ RenderRegion GlGeometry::getBounds() const static_cast(ceil(right - floor(left))), static_cast(ceil(bottom - floor(top))), }; - if (bounds.w < 0 || bounds.h < 0) { - return mBounds; - } else { - return bounds; - } + if (bounds.w < 0 || bounds.h < 0) return mBounds; + else return bounds; } } diff --git a/src/renderer/gl_engine/tvgGlGpuBuffer.cpp b/src/renderer/gl_engine/tvgGlGpuBuffer.cpp index 1c06f1f3..06cdf31a 100644 --- a/src/renderer/gl_engine/tvgGlGpuBuffer.cpp +++ b/src/renderer/gl_engine/tvgGlGpuBuffer.cpp @@ -26,7 +26,7 @@ #include /************************************************************************/ -/* Internal Class Implementation */ +/* GlGpuBuffer Implementation */ /************************************************************************/ static GLint _getGpuBufferAlign() @@ -39,7 +39,26 @@ static GLint _getGpuBufferAlign() } return offset; -} +} + + +void GlGpuBuffer::updateBufferData(Target target, uint32_t size, const void* data) +{ + GL_CHECK(glBufferData(static_cast(target), size, data, GL_STATIC_DRAW)); +} + + +void GlGpuBuffer::bind(Target target) +{ + GL_CHECK(glBindBuffer(static_cast(target), mGlBufferId)); +} + + +void GlGpuBuffer::unbind(Target target) +{ + GL_CHECK(glBindBuffer(static_cast(target), 0)); +} + GlGpuBuffer::GlGpuBuffer() { @@ -56,27 +75,16 @@ GlGpuBuffer::~GlGpuBuffer() } } - -void GlGpuBuffer::updateBufferData(Target target, uint32_t size, const void* data) -{ - GL_CHECK(glBufferData(static_cast(target), size, data, GL_STATIC_DRAW)); -} - -void GlGpuBuffer::bind(Target target) -{ - GL_CHECK(glBindBuffer(static_cast(target), mGlBufferId)); -} - -void GlGpuBuffer::unbind(Target target) -{ - GL_CHECK(glBindBuffer(static_cast(target), 0)); -} +/************************************************************************/ +/* GlStageBuffer Implementation */ +/************************************************************************/ GlStageBuffer::GlStageBuffer() : mVao(0), mGpuBuffer(), mGpuIndexBuffer() { GL_CHECK(glGenVertexArrays(1, &mVao)); } + GlStageBuffer::~GlStageBuffer() { if (mVao) { @@ -85,6 +93,7 @@ GlStageBuffer::~GlStageBuffer() } } + uint32_t GlStageBuffer::push(void *data, uint32_t size, bool alignGpuOffset) { if (alignGpuOffset) alignOffset(size); @@ -102,6 +111,7 @@ uint32_t GlStageBuffer::push(void *data, uint32_t size, bool alignGpuOffset) return offset; } + uint32_t GlStageBuffer::pushIndex(void *data, uint32_t size) { uint32_t offset = mIndexBuffer.count; @@ -117,6 +127,7 @@ uint32_t GlStageBuffer::pushIndex(void *data, uint32_t size) return offset; } + bool GlStageBuffer::flushToGPU() { if (mStageBuffer.empty() || mIndexBuffer.empty()) { @@ -140,6 +151,7 @@ bool GlStageBuffer::flushToGPU() return true; } + void GlStageBuffer::bind() { glBindVertexArray(mVao); @@ -148,6 +160,7 @@ void GlStageBuffer::bind() mGpuIndexBuffer.bind(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER); } + void GlStageBuffer::unbind() { glBindVertexArray(0); @@ -156,11 +169,13 @@ void GlStageBuffer::unbind() mGpuIndexBuffer.unbind(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER); } + GLuint GlStageBuffer::getBufferId() { return mGpuBuffer.getBufferId(); } + void GlStageBuffer::alignOffset(uint32_t size) { diff --git a/src/renderer/gl_engine/tvgGlGpuBuffer.h b/src/renderer/gl_engine/tvgGlGpuBuffer.h index 40a79743..5fbe1724 100644 --- a/src/renderer/gl_engine/tvgGlGpuBuffer.h +++ b/src/renderer/gl_engine/tvgGlGpuBuffer.h @@ -40,8 +40,8 @@ public: void updateBufferData(Target target, uint32_t size, const void* data); void bind(Target target); void unbind(Target target); - uint32_t getBufferId() { return mGlBufferId; } + private: uint32_t mGlBufferId = 0; @@ -53,19 +53,15 @@ public: ~GlStageBuffer(); uint32_t push(void* data, uint32_t size, bool alignGpuOffset = false); - uint32_t pushIndex(void* data, uint32_t size); - bool flushToGPU(); - void bind(); - void unbind(); - GLuint getBufferId(); + private: void alignOffset(uint32_t size); -private: + GLuint mVao = 0; GlGpuBuffer mGpuBuffer = {}; GlGpuBuffer mGpuIndexBuffer = {}; diff --git a/src/renderer/gl_engine/tvgGlProgram.cpp b/src/renderer/gl_engine/tvgGlProgram.cpp index 5cc30122..c8dc8e38 100644 --- a/src/renderer/gl_engine/tvgGlProgram.cpp +++ b/src/renderer/gl_engine/tvgGlProgram.cpp @@ -29,6 +29,43 @@ uint32_t GlProgram::mCurrentProgram = 0; +void GlProgram::linkProgram(std::shared_ptr shader) +{ + GLint linked; + + // Create the program object + uint32_t progObj = glCreateProgram(); + assert(progObj); + + glAttachShader(progObj, shader->getVertexShader()); + glAttachShader(progObj, shader->getFragmentShader()); + + // Link the program + glLinkProgram(progObj); + + // Check the link status + glGetProgramiv(progObj, GL_LINK_STATUS, &linked); + + if (!linked) + { + GLint infoLen = 0; + glGetProgramiv(progObj, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 0) + { + auto infoLog = static_cast(malloc(sizeof(char) * infoLen)); + glGetProgramInfoLog(progObj, infoLen, NULL, infoLog); + TVGERR("GL_ENGINE", "Error linking shader: %s", infoLog); + free(infoLog); + + } + glDeleteProgram(progObj); + progObj = 0; + assert(0); + } + mProgramObj = progObj; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -149,40 +186,3 @@ void GlProgram::setUniform4x4Value(int32_t location, int count, const float* val { GL_CHECK(glUniformMatrix4fv(location, count, GL_FALSE, &values[0])); } - -void GlProgram::linkProgram(std::shared_ptr shader) -{ - GLint linked; - - // Create the program object - uint32_t progObj = glCreateProgram(); - assert(progObj); - - glAttachShader(progObj, shader->getVertexShader()); - glAttachShader(progObj, shader->getFragmentShader()); - - // Link the program - glLinkProgram(progObj); - - // Check the link status - glGetProgramiv(progObj, GL_LINK_STATUS, &linked); - - if (!linked) - { - GLint infoLen = 0; - glGetProgramiv(progObj, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen > 0) - { - auto infoLog = static_cast(malloc(sizeof(char) * infoLen)); - glGetProgramInfoLog(progObj, infoLen, NULL, infoLog); - TVGERR("GL_ENGINE", "Error linking shader: %s", infoLog); - free(infoLog); - - } - glDeleteProgram(progObj); - progObj = 0; - assert(0); - } - mProgramObj = progObj; -} - diff --git a/src/renderer/gl_engine/tvgGlRenderTask.cpp b/src/renderer/gl_engine/tvgGlRenderTask.cpp index a67f3dc8..1c9ba692 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTask.cpp @@ -24,9 +24,6 @@ #include "tvgGlProgram.h" #include "tvgGlRenderPass.h" -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ GlRenderTask::GlRenderTask(GlProgram* program, GlRenderTask* other): mProgram(program) { diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index 5305f521..4b8f11b1 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -803,12 +803,10 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp) } - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ - bool GlRenderer::clear() { clearDisposes(); diff --git a/src/renderer/gl_engine/tvgGlShader.cpp b/src/renderer/gl_engine/tvgGlShader.cpp index 99f63f0a..55c8e5c5 100644 --- a/src/renderer/gl_engine/tvgGlShader.cpp +++ b/src/renderer/gl_engine/tvgGlShader.cpp @@ -23,35 +23,9 @@ #include "tvgGlShader.h" /************************************************************************/ -/* External Class Implementation */ +/* Internal Class Implementation */ /************************************************************************/ -shared_ptr GlShader::gen(const char* vertSrc, const char* fragSrc) -{ - shared_ptr shader = make_shared(); - shader->createShader(vertSrc, fragSrc); - return shader; -} - - -GlShader::~GlShader() -{ - glDeleteShader(mVtShader); - glDeleteShader(mFrShader); -} - -uint32_t GlShader::getVertexShader() -{ - return mVtShader; -} - - -uint32_t GlShader::getFragmentShader() -{ - return mFrShader; -} - - void GlShader::createShader(const char* vertSrc, const char* fragSrc) { mVtShader = compileShader(GL_VERTEX_SHADER, const_cast(vertSrc)); @@ -110,3 +84,31 @@ uint32_t GlShader::compileShader(uint32_t type, char* shaderSrc) return shader; } +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +shared_ptr GlShader::gen(const char* vertSrc, const char* fragSrc) +{ + shared_ptr shader = make_shared(); + shader->createShader(vertSrc, fragSrc); + return shader; +} + + +GlShader::~GlShader() +{ + glDeleteShader(mVtShader); + glDeleteShader(mFrShader); +} + +uint32_t GlShader::getVertexShader() +{ + return mVtShader; +} + + +uint32_t GlShader::getFragmentShader() +{ + return mFrShader; +} \ No newline at end of file diff --git a/src/renderer/gl_engine/tvgGlTessellator.h b/src/renderer/gl_engine/tvgGlTessellator.h index 9e0de889..07753a60 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.h +++ b/src/renderer/gl_engine/tvgGlTessellator.h @@ -61,7 +61,7 @@ private: Polygon *makePoly(Vertex* v, int32_t winding); void emitPoly(MonotonePolygon* poly); void emitTriangle(Vertex* p1, Vertex* p2, Vertex* p3); -private: + FillRule fillRule = FillRule::Winding; std::unique_ptr pHeap; Array outlines; @@ -134,7 +134,6 @@ private: void lineTo(const Point& pt); void cubicTo(const Point& pt1, const Point& pt2, const Point& pt3); -private: Array* mCmds; Array* mPts; uint32_t mDashCount; diff --git a/src/renderer/sw_engine/tvgSwFill.cpp b/src/renderer/sw_engine/tvgSwFill.cpp index 15c1624f..11502351 100644 --- a/src/renderer/sw_engine/tvgSwFill.cpp +++ b/src/renderer/sw_engine/tvgSwFill.cpp @@ -66,15 +66,17 @@ static void _calculateCoefficients(const SwFill* fill, uint32_t x, uint32_t y, f static uint32_t _estimateAAMargin(const Fill* fdata) { constexpr float marginScalingFactor = 800.0f; + if (fdata->type() == Type::RadialGradient) { - auto radius = P(static_cast(fdata))->r; + auto radius = RADIAL(fdata)->r; return tvg::zero(radius) ? 0 : static_cast(marginScalingFactor / radius); + } else { + auto grad = LINEAR(fdata); + Point p1 {grad->x1, grad->y1}; + Point p2 {grad->x2, grad->y2}; + auto len = length(&p1, &p2); + return tvg::zero(len) ? 0 : static_cast(marginScalingFactor / len); } - auto grad = P(static_cast(fdata)); - Point p1 {grad->x1, grad->y1}; - Point p2 {grad->x2, grad->y2}; - auto len = length(&p1, &p2); - return tvg::zero(len) ? 0 : static_cast(marginScalingFactor / len); } @@ -129,7 +131,6 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* if (!fill->ctable) { fill->ctable = static_cast(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t))); - if (!fill->ctable) return false; } const Fill::ColorStop* colors; @@ -145,7 +146,6 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* auto g = pColors->g; auto b = pColors->b; auto rgba = surface->join(r, g, b, a); - auto inc = 1.0f / static_cast(GRADIENT_STOP_SIZE); auto pos = 1.5f * inc; uint32_t i = 0; @@ -173,6 +173,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* auto next = curr + 1; auto delta = 1.0f / (next->offset - curr->offset); auto a2 = MULTIPLY(next->a, opacity); + if (!fill->translucent && a2 < 255) fill->translucent = true; auto rgba2 = surface->join(next->r, next->g, next->b, a2); @@ -181,10 +182,8 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* auto t = (pos - curr->offset) * delta; auto dist = static_cast(255 * t); auto dist2 = 255 - dist; - auto color = INTERPOLATE(rgba, rgba2, dist2); fill->ctable[i] = ALPHA_BLEND((color | 0xff000000), (color >> 24)); - ++i; pos += inc; } @@ -195,8 +194,9 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* } rgba = ALPHA_BLEND((rgba | 0xff000000), a); - for (; i < GRADIENT_STOP_SIZE; ++i) + for (; i < GRADIENT_STOP_SIZE; ++i) { fill->ctable[i] = rgba; + } //For repeat fill spread apply anti-aliasing between the last and first colors, //othewise make sure the last color stop is represented at the end of the table. @@ -210,7 +210,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix& pTransform) { float x1, x2, y1, y2; - if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; + linear->linear(&x1, &y1, &x2, &y2); fill->linear.dx = x2 - x1; fill->linear.dy = y2 - y1; @@ -244,12 +244,8 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix& pT bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix& pTransform) { - auto cx = P(radial)->cx; - auto cy = P(radial)->cy; - auto r = P(radial)->r; - auto fx = P(radial)->fx; - auto fy = P(radial)->fy; - auto fr = P(radial)->fr; + float cx, cy, r, fx, fy, fr; + radial->radial(&cx, &cy, &r, &fx, &fy, &fr); if (tvg::zero(r)) { fill->solid = true; diff --git a/src/renderer/sw_engine/tvgSwRaster.cpp b/src/renderer/sw_engine/tvgSwRaster.cpp index b556bb8e..2b678387 100644 --- a/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/src/renderer/sw_engine/tvgSwRaster.cpp @@ -35,6 +35,7 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ + constexpr auto DOWN_SCALE_TOLERANCE = 0.5f; struct FillLinear diff --git a/src/renderer/tvgAnimation.cpp b/src/renderer/tvgAnimation.cpp index 4e7c8c4c..270adb8d 100644 --- a/src/renderer/tvgAnimation.cpp +++ b/src/renderer/tvgAnimation.cpp @@ -23,13 +23,6 @@ #include "tvgFrameModule.h" #include "tvgAnimation.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ Animation::~Animation() { @@ -44,7 +37,7 @@ Animation::Animation() : pImpl(new Impl) Result Animation::frame(float no) noexcept { - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return Result::InsufficientCondition; if (!loader->animatable()) return Result::NonSupport; @@ -62,7 +55,7 @@ Picture* Animation::picture() const noexcept float Animation::curFrame() const noexcept { - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return 0; if (!loader->animatable()) return 0; @@ -73,7 +66,7 @@ float Animation::curFrame() const noexcept float Animation::totalFrame() const noexcept { - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return 0; if (!loader->animatable()) return 0; @@ -84,7 +77,7 @@ float Animation::totalFrame() const noexcept float Animation::duration() const noexcept { - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return 0; if (!loader->animatable()) return 0; @@ -97,7 +90,7 @@ Result Animation::segment(float begin, float end) noexcept { if (begin < 0.0 || end > 1.0 || begin > end) return Result::InvalidArguments; - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return Result::InsufficientCondition; if (!loader->animatable()) return Result::NonSupport; @@ -109,7 +102,7 @@ Result Animation::segment(float begin, float end) noexcept Result Animation::segment(float *begin, float *end) noexcept { - auto loader = pImpl->picture->pImpl->loader; + auto loader = PICTURE(pImpl->picture)->loader; if (!loader) return Result::InsufficientCondition; if (!loader->animatable()) return Result::NonSupport; if (!begin && !end) return Result::InvalidArguments; diff --git a/src/renderer/tvgCanvas.cpp b/src/renderer/tvgCanvas.cpp index eb0d38ac..e2f708f9 100644 --- a/src/renderer/tvgCanvas.cpp +++ b/src/renderer/tvgCanvas.cpp @@ -22,11 +22,7 @@ #include "tvgCanvas.h" -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -Canvas::Canvas(RenderMethod *pRenderer):pImpl(new Impl(pRenderer)) +Canvas::Canvas():pImpl(new Impl) { } diff --git a/src/renderer/tvgCanvas.h b/src/renderer/tvgCanvas.h index f609df4c..35085b66 100644 --- a/src/renderer/tvgCanvas.h +++ b/src/renderer/tvgCanvas.h @@ -34,10 +34,9 @@ struct Canvas::Impl RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX}; Status status = Status::Synced; - Impl(RenderMethod* pRenderer) : scene(Scene::gen()), renderer(pRenderer) + Impl() : scene(Scene::gen()) { scene->ref(); - renderer->ref(); } ~Impl() @@ -77,8 +76,8 @@ struct Canvas::Impl auto m = Matrix{1, 0, 0, 0, 1, 0, 0, 0, 1}; - if (paint) P(paint)->update(renderer, m, clips, 255, flag); - else PP(scene)->update(renderer, m, clips, 255, flag); + if (paint) PAINT(paint)->update(renderer, m, clips, 255, flag); + else PAINT(scene)->update(renderer, m, clips, 255, flag); status = Status::Updating; return Result::Success; @@ -96,7 +95,7 @@ struct Canvas::Impl if (!renderer->preRender()) return Result::InsufficientCondition; - if (!PP(scene)->render(renderer) || !renderer->postRender()) return Result::InsufficientCondition; + if (!PAINT(scene)->render(renderer) || !renderer->postRender()) return Result::InsufficientCondition; status = Status::Drawing; diff --git a/src/renderer/tvgCommon.h b/src/renderer/tvgCommon.h index 8e56784c..53de29e9 100644 --- a/src/renderer/tvgCommon.h +++ b/src/renderer/tvgCommon.h @@ -75,10 +75,7 @@ using Size = Point; uint16_t THORVG_VERSION_NUMBER(); - -#define P(A) ((A)->pImpl) //Access to pimpl. -#define PP(A) (((Paint*)(A))->pImpl) //Access to pimpl. - +#define PIMPL(INST, CLASS) ((CLASS::Impl*)INST->pImpl) //Access to pimpl #define TVG_DELETE(PAINT) \ if (PAINT->refCnt() == 0) delete(PAINT) diff --git a/src/renderer/tvgFill.cpp b/src/renderer/tvgFill.cpp index ce3f0ff6..b58e1989 100644 --- a/src/renderer/tvgFill.cpp +++ b/src/renderer/tvgFill.cpp @@ -22,60 +22,12 @@ #include "tvgFill.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -Fill* RadialGradient::Impl::duplicate() -{ - auto ret = RadialGradient::gen(); - if (!ret) return nullptr; - - ret->pImpl->cx = cx; - ret->pImpl->cy = cy; - ret->pImpl->r = r; - ret->pImpl->fx = fx; - ret->pImpl->fy = fy; - ret->pImpl->fr = fr; - - return ret; -} - - -Result RadialGradient::Impl::radial(float cx, float cy, float r, float fx, float fy, float fr) -{ - if (r < 0 || fr < 0) return Result::InvalidArguments; - - this->cx = cx; - this->cy = cy; - this->r = r; - this->fx = fx; - this->fy = fy; - this->fr = fr; - - return Result::Success; -}; - - -Fill* LinearGradient::Impl::duplicate() -{ - auto ret = LinearGradient::gen(); - if (!ret) return nullptr; - - ret->pImpl->x1 = x1; - ret->pImpl->y1 = y1; - ret->pImpl->x2 = x2; - ret->pImpl->y2 = y2; - - return ret; -}; - /************************************************************************/ -/* External Class Implementation */ +/* Fill Class Implementation */ /************************************************************************/ -Fill::Fill():pImpl(new Impl()) +Fill::Fill() { } @@ -88,32 +40,13 @@ Fill::~Fill() Result Fill::colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept { - if ((!colorStops && cnt > 0) || (colorStops && cnt == 0)) return Result::InvalidArguments; - - if (cnt == 0) { - if (pImpl->colorStops) { - free(pImpl->colorStops); - pImpl->colorStops = nullptr; - pImpl->cnt = 0; - } - return Result::Success; - } - - if (pImpl->cnt != cnt) { - pImpl->colorStops = static_cast(realloc(pImpl->colorStops, cnt * sizeof(ColorStop))); - } - - pImpl->cnt = cnt; - memcpy(pImpl->colorStops, colorStops, cnt * sizeof(ColorStop)); - - return Result::Success; + return pImpl->update(colorStops, cnt); } uint32_t Fill::colorStops(const ColorStop** colorStops) const noexcept { if (colorStops) *colorStops = pImpl->colorStops; - return pImpl->cnt; } @@ -121,7 +54,6 @@ uint32_t Fill::colorStops(const ColorStop** colorStops) const noexcept Result Fill::spread(FillSpread s) noexcept { pImpl->spread = s; - return Result::Success; } @@ -151,34 +83,26 @@ Fill* Fill::duplicate() const noexcept } -RadialGradient::RadialGradient():pImpl(new Impl()) -{ - Fill::pImpl->method(new FillDup(pImpl)); -} +/************************************************************************/ +/* RadialGradient Class Implementation */ +/************************************************************************/ -RadialGradient::~RadialGradient() +RadialGradient::RadialGradient() { - delete(pImpl); + Fill::pImpl = new Impl; } Result RadialGradient::radial(float cx, float cy, float r, float fx, float fy, float fr) noexcept { - return pImpl->radial(cx, cy, r, fx, fy, fr); + return RADIAL(this)->radial(cx, cy, r, fx, fy, fr); } Result RadialGradient::radial(float* cx, float* cy, float* r, float* fx, float* fy, float* fr) const noexcept { - if (cx) *cx = pImpl->cx; - if (cy) *cy = pImpl->cy; - if (r) *r = pImpl->r; - if (fx) *fx = pImpl->fx; - if (fy) *fy = pImpl->fy; - if (fr) *fr = pImpl->fr; - - return Result::Success; + return RADIAL(this)->radial(cx, cy, r, fx, fy, fr); } @@ -194,37 +118,26 @@ Type RadialGradient::type() const noexcept } -LinearGradient::LinearGradient():pImpl(new Impl()) -{ - Fill::pImpl->method(new FillDup(pImpl)); -} +/************************************************************************/ +/* LinearGradient Class Implementation */ +/************************************************************************/ -LinearGradient::~LinearGradient() +LinearGradient::LinearGradient() { - delete(pImpl); + Fill::pImpl = new Impl; } Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept { - pImpl->x1 = x1; - pImpl->y1 = y1; - pImpl->x2 = x2; - pImpl->y2 = y2; - - return Result::Success; + return LINEAR(this)->linear(x1, y1, x2, y2); } Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept { - if (x1) *x1 = pImpl->x1; - if (x2) *x2 = pImpl->x2; - if (y1) *y1 = pImpl->y1; - if (y2) *y2 = pImpl->y2; - - return Result::Success; + return LINEAR(this)->linear(x1, y1, x2, y2); } diff --git a/src/renderer/tvgFill.h b/src/renderer/tvgFill.h index f7e4bb83..4cc59991 100644 --- a/src/renderer/tvgFill.h +++ b/src/renderer/tvgFill.h @@ -27,80 +27,143 @@ #include #include "tvgCommon.h" -template -struct DuplicateMethod -{ - virtual ~DuplicateMethod() {} - virtual T* duplicate() = 0; -}; - -template -struct FillDup : DuplicateMethod -{ - T* inst = nullptr; - - FillDup(T* _inst) : inst(_inst) {} - ~FillDup() {} - - Fill* duplicate() override - { - return inst->duplicate(); - } -}; +#define LINEAR(A) PIMPL(A, LinearGradient) +#define RADIAL(A) PIMPL(A, RadialGradient) struct Fill::Impl { ColorStop* colorStops = nullptr; Matrix transform = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - uint32_t cnt = 0; - DuplicateMethod* dup = nullptr; - FillSpread spread; + uint16_t cnt = 0; + FillSpread spread = FillSpread::Pad; - ~Impl() + virtual ~Impl() { - delete(dup); free(colorStops); } - void method(DuplicateMethod* dup) + void copy(Fill::Impl* dup) { - this->dup = dup; + cnt = dup->cnt; + spread = dup->spread; + colorStops = static_cast(malloc(sizeof(ColorStop) * dup->cnt)); + memcpy(colorStops, dup->colorStops, sizeof(ColorStop) * dup->cnt); + transform = dup->transform; } - Fill* duplicate() + Result update(const ColorStop* colorStops, uint32_t cnt) { - auto ret = dup->duplicate(); + if ((!colorStops && cnt > 0) || (colorStops && cnt == 0)) return Result::InvalidArguments; - ret->pImpl->cnt = cnt; - ret->pImpl->spread = spread; - ret->pImpl->colorStops = static_cast(malloc(sizeof(ColorStop) * cnt)); - memcpy(ret->pImpl->colorStops, colorStops, sizeof(ColorStop) * cnt); - ret->pImpl->transform = transform; + if (cnt == 0) { + if (this->colorStops) { + free(this->colorStops); + this->colorStops = nullptr; + this->cnt = 0; + } + return Result::Success; + } - return ret; + if (cnt != this->cnt) { + this->colorStops = static_cast(realloc(this->colorStops, cnt * sizeof(ColorStop))); + } + + this->cnt = cnt; + memcpy(this->colorStops, colorStops, cnt * sizeof(ColorStop)); + + return Result::Success; } + + virtual Fill* duplicate() = 0; }; -struct RadialGradient::Impl +struct RadialGradient::Impl : Fill::Impl { float cx = 0.0f, cy = 0.0f; float fx = 0.0f, fy = 0.0f; float r = 0.0f, fr = 0.0f; - Fill* duplicate(); - Result radial(float cx, float cy, float r, float fx, float fy, float fr); + Fill* duplicate() override + { + auto ret = RadialGradient::gen(); + RADIAL(ret)->copy(this); + RADIAL(ret)->cx = cx; + RADIAL(ret)->cy = cy; + RADIAL(ret)->r = r; + RADIAL(ret)->fx = fx; + RADIAL(ret)->fy = fy; + RADIAL(ret)->fr = fr; + + return ret; + } + + Result radial(float cx, float cy, float r, float fx, float fy, float fr) + { + if (r < 0 || fr < 0) return Result::InvalidArguments; + + this->cx = cx; + this->cy = cy; + this->r = r; + this->fx = fx; + this->fy = fy; + this->fr = fr; + + return Result::Success; + } + + Result radial(float* cx, float* cy, float* r, float* fx, float* fy, float* fr) const + { + if (cx) *cx = this->cx; + if (cy) *cy = this->cy; + if (r) *r = this->r; + if (fx) *fx = this->fx; + if (fy) *fy = this->fy; + if (fr) *fr = this->fr; + + return Result::Success; + } }; -struct LinearGradient::Impl +struct LinearGradient::Impl : Fill::Impl { float x1 = 0.0f; float y1 = 0.0f; float x2 = 0.0f; float y2 = 0.0f; - Fill* duplicate(); + Fill* duplicate() override + { + auto ret = LinearGradient::gen(); + LINEAR(ret)->copy(this); + LINEAR(ret)->x1 = x1; + LINEAR(ret)->y1 = y1; + LINEAR(ret)->x2 = x2; + LINEAR(ret)->y2 = y2; + + return ret; + } + + Result linear(float x1, float y1, float x2, float y2) noexcept + { + this->x1 = x1; + this->y1 = y1; + this->x2 = x2; + this->y2 = y2; + + return Result::Success; + } + + Result linear(float* x1, float* y1, float* x2, float* y2) const noexcept + { + if (x1) *x1 = this->x1; + if (x2) *x2 = this->x2; + if (y1) *y1 = this->y1; + if (y2) *y2 = this->y2; + + return Result::Success; + } }; diff --git a/src/renderer/tvgGlCanvas.cpp b/src/renderer/tvgGlCanvas.cpp index 08f41f6b..b829ced8 100644 --- a/src/renderer/tvgGlCanvas.cpp +++ b/src/renderer/tvgGlCanvas.cpp @@ -24,38 +24,20 @@ #ifdef THORVG_GL_RASTER_SUPPORT #include "tvgGlRenderer.h" -#else - class GlRenderer : public RenderMethod - { - //Non Supported. Dummy Class */ - }; #endif -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -struct GlCanvas::Impl +GlCanvas::GlCanvas() { -}; - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - #ifdef THORVG_GL_RASTER_SUPPORT -GlCanvas::GlCanvas() : Canvas(GlRenderer::gen()), pImpl(nullptr) -#else -GlCanvas::GlCanvas() : Canvas(nullptr), pImpl(nullptr) + pImpl->renderer = GlRenderer::gen(); + pImpl->renderer->ref(); #endif -{ } GlCanvas::~GlCanvas() { - delete(pImpl); + //TODO: } @@ -64,20 +46,20 @@ Result GlCanvas::target(int32_t id, uint32_t w, uint32_t h, ColorSpace cs) noexc #ifdef THORVG_GL_RASTER_SUPPORT if (cs != ColorSpace::ABGR8888S) return Result::NonSupport; - if (Canvas::pImpl->status != Status::Damaged && Canvas::pImpl->status != Status::Synced) { + if (pImpl->status != Status::Damaged && pImpl->status != Status::Synced) { return Result::InsufficientCondition; } //We know renderer type, avoid dynamic_cast for performance. - auto renderer = static_cast(Canvas::pImpl->renderer); + auto renderer = static_cast(pImpl->renderer); if (!renderer) return Result::MemoryCorruption; if (!renderer->target(id, w, h)) return Result::Unknown; - Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; - renderer->viewport(Canvas::pImpl->vport); + pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; + renderer->viewport(pImpl->vport); //Paints must be updated again with this new target. - Canvas::pImpl->status = Status::Damaged; + pImpl->status = Status::Damaged; return Result::Success; #endif diff --git a/src/renderer/tvgIteratorAccessor.h b/src/renderer/tvgIteratorAccessor.h index 46e900a5..2f550126 100644 --- a/src/renderer/tvgIteratorAccessor.h +++ b/src/renderer/tvgIteratorAccessor.h @@ -34,7 +34,7 @@ public: //Utility Method: Iterator Accessor static Iterator* iterator(const Paint* paint) { - return paint->pImpl->iterator(); + return PAINT(paint)->iterator(); } }; diff --git a/src/renderer/tvgPaint.cpp b/src/renderer/tvgPaint.cpp index 208f164e..fa7e1087 100644 --- a/src/renderer/tvgPaint.cpp +++ b/src/renderer/tvgPaint.cpp @@ -33,10 +33,10 @@ #define PAINT_METHOD(ret, METHOD) \ switch (paint->type()) { \ - case Type::Shape: ret = P((Shape*)paint)->METHOD; break; \ - case Type::Scene: ret = P((Scene*)paint)->METHOD; break; \ - case Type::Picture: ret = P((Picture*)paint)->METHOD; break; \ - case Type::Text: ret = P((Text*)paint)->METHOD; break; \ + case Type::Shape: ret = SHAPE(paint)->METHOD; break; \ + case Type::Scene: ret = SCENE(paint)->METHOD; break; \ + case Type::Picture: ret = PICTURE(paint)->METHOD; break; \ + case Type::Text: ret = TEXT(paint)->METHOD; break; \ default: ret = {}; \ } @@ -170,40 +170,6 @@ Paint* Paint::Impl::duplicate(Paint* ret) } -bool Paint::Impl::rotate(float degree) -{ - if (tr.overriding) return false; - if (tvg::equal(degree, tr.degree)) return true; - tr.degree = degree; - renderFlag |= RenderUpdateFlag::Transform; - - return true; -} - - -bool Paint::Impl::scale(float factor) -{ - if (tr.overriding) return false; - if (tvg::equal(factor, tr.scale)) return true; - tr.scale = factor; - renderFlag |= RenderUpdateFlag::Transform; - - return true; -} - - -bool Paint::Impl::translate(float x, float y) -{ - if (tr.overriding) return false; - if (tvg::equal(x, tr.m.e13) && tvg::equal(y, tr.m.e23)) return true; - tr.m.e13 = x; - tr.m.e23 = y; - renderFlag |= RenderUpdateFlag::Transform; - - return true; -} - - bool Paint::Impl::render(RenderMethod* renderer) { if (opacity == 0) return true; @@ -214,7 +180,7 @@ bool Paint::Impl::render(RenderMethod* renderer) RenderRegion region; PAINT_METHOD(region, bounds(renderer)); - if (MASK_REGION_MERGING(maskData->method)) region.add(P(maskData->target)->bounds(renderer)); + if (MASK_REGION_MERGING(maskData->method)) region.add(PAINT(maskData->target)->bounds(renderer)); if (region.w == 0 || region.h == 0) return true; cmp = renderer->target(region, MASK_TO_COLORSPACE(renderer, maskData->method), CompositionFlag::Masking); if (renderer->beginComposite(cmp, MaskMethod::None, 255)) { @@ -251,7 +217,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Arraytarget; auto method = maskData->method; - P(target)->ctxFlag &= ~ContextFlag::FastTrack; //reset + PAINT(target)->ctxFlag &= ~ContextFlag::FastTrack; //reset /* If the transformation has no rotational factors and the Alpha(InvAlpha) Masking involves a simple rectangle, we can optimize by using the viewport instead of the regular Alphaing sequence for improved performance. */ @@ -260,31 +226,31 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, ArrayfillColor(nullptr, nullptr, nullptr, &a); //no gradient fill & no maskings of the masking target. - if (!shape->fill() && !(PP(shape)->maskData)) { - if ((method == MaskMethod::Alpha && a == 255 && PP(shape)->opacity == 255) || (method == MaskMethod::InvAlpha && (a == 0 || PP(shape)->opacity == 0))) { + if (!shape->fill() && !(PAINT(shape)->maskData)) { + if ((method == MaskMethod::Alpha && a == 255 && PAINT(shape)->opacity == 255) || (method == MaskMethod::InvAlpha && (a == 0 || PAINT(shape)->opacity == 0))) { viewport = renderer->viewport(); if ((compFastTrack = _compFastTrack(renderer, target, pm, viewport)) == Result::Success) { - P(target)->ctxFlag |= ContextFlag::FastTrack; + PAINT(target)->ctxFlag |= ContextFlag::FastTrack; } } } } if (compFastTrack == Result::InsufficientCondition) { - trd = P(target)->update(renderer, pm, clips, 255, pFlag, false); + trd = PAINT(target)->update(renderer, pm, clips, 255, pFlag, false); } } /* 2. Clipping */ if (this->clipper) { - P(this->clipper)->ctxFlag &= ~ContextFlag::FastTrack; //reset + PAINT(this->clipper)->ctxFlag &= ~ContextFlag::FastTrack; //reset viewport = renderer->viewport(); /* TODO: Intersect the clipper's clipper, if both are FastTrack. Update the subsequent clipper first and check its ctxFlag. */ - if (!P(this->clipper)->clipper && (compFastTrack = _compFastTrack(renderer, this->clipper, pm, viewport)) == Result::Success) { - P(this->clipper)->ctxFlag |= ContextFlag::FastTrack; + if (!PAINT(this->clipper)->clipper && (compFastTrack = _compFastTrack(renderer, this->clipper, pm, viewport)) == Result::Success) { + PAINT(this->clipper)->ctxFlag |= ContextFlag::FastTrack; } if (compFastTrack == Result::InsufficientCondition) { - trd = P(this->clipper)->update(renderer, pm, clips, 255, pFlag, true); + trd = PAINT(this->clipper)->update(renderer, pm, clips, 255, pFlag, true); clips.push(trd); } } @@ -354,37 +320,11 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme } -void Paint::Impl::reset() -{ - if (clipper) { - clipper->unref(); - clipper = nullptr; - } - - if (maskData) { - maskData->target->unref(); - free(maskData); - maskData = nullptr; - } - - tvg::identity(&tr.m); - tr.degree = 0.0f; - tr.scale = 1.0f; - tr.overriding = false; - - blendMethod = BlendMethod::Normal; - renderFlag = RenderUpdateFlag::None; - ctxFlag = ContextFlag::Default; - opacity = 255; - paint->id = 0; -} - - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -Paint :: Paint() : pImpl(new Impl(this)) +Paint :: Paint() { } @@ -464,13 +404,7 @@ Result Paint::mask(Paint* target, MaskMethod method) noexcept MaskMethod Paint::mask(const Paint** target) const noexcept { - if (pImpl->maskData) { - if (target) *target = pImpl->maskData->target; - return pImpl->maskData->method; - } else { - if (target) *target = nullptr; - return MaskMethod::None; - } + return pImpl->mask(target); } @@ -495,37 +429,20 @@ Result Paint::blend(BlendMethod method) noexcept { //TODO: Remove later if (method == BlendMethod::Hue || method == BlendMethod::Saturation || method == BlendMethod::Color || method == BlendMethod::Luminosity || method == BlendMethod::HardMix) return Result::NonSupport; - - if (pImpl->blendMethod != method) { - pImpl->blendMethod = method; - pImpl->renderFlag |= RenderUpdateFlag::Blend; - } - + pImpl->blend(method); return Result::Success; } uint8_t Paint::ref() noexcept { - if (pImpl->refCnt == UINT8_MAX) TVGERR("RENDERER", "Reference Count Overflow!"); - else ++pImpl->refCnt; - - return pImpl->refCnt; + return pImpl->ref(); } uint8_t Paint::unref(bool free) noexcept { - if (pImpl->refCnt > 0) --pImpl->refCnt; - else TVGERR("RENDERER", "Corrupted Reference Count!"); - - if (free && pImpl->refCnt == 0) { - //TODO: use the global dismiss function? - delete(this); - return 0; - } - - return pImpl->refCnt; + return pImpl->unref(free); } diff --git a/src/renderer/tvgPaint.h b/src/renderer/tvgPaint.h index 001a0017..070e5369 100644 --- a/src/renderer/tvgPaint.h +++ b/src/renderer/tvgPaint.h @@ -26,6 +26,8 @@ #include "tvgRender.h" #include "tvgMath.h" +#define PAINT(A) PIMPL(A, Paint) + namespace tvg { enum ContextFlag : uint8_t {Default = 0, FastTrack = 1}; @@ -83,7 +85,7 @@ namespace tvg reset(); } - ~Impl() + virtual ~Impl() { if (maskData) { maskData->target->unref(); @@ -93,6 +95,32 @@ namespace tvg if (renderer && (renderer->unref() == 0)) delete(renderer); } + uint8_t ref() + { + if (refCnt == UINT8_MAX) TVGERR("RENDERER", "Reference Count Overflow!"); + else ++refCnt; + return refCnt; + } + + uint8_t unref(bool free) + { + if (refCnt > 0) --refCnt; + else TVGERR("RENDERER", "Corrupted Reference Count!"); + + if (free && refCnt == 0) { + //TODO: use the global dismiss function? + delete(this); + return 0; + } + + return refCnt; + } + + void update(RenderUpdateFlag flag) + { + renderFlag |= flag; + } + bool transform(const Matrix& m) { if (&tr.m != &m) tr.m = m; @@ -143,16 +171,87 @@ namespace tvg return true; } + MaskMethod mask(const Paint** target) const + { + if (maskData) { + if (target) *target = maskData->target; + return maskData->method; + } else { + if (target) *target = nullptr; + return MaskMethod::None; + } + } + + void reset() + { + if (clipper) { + clipper->unref(); + clipper = nullptr; + } + + if (maskData) { + maskData->target->unref(); + free(maskData); + maskData = nullptr; + } + + tvg::identity(&tr.m); + tr.degree = 0.0f; + tr.scale = 1.0f; + tr.overriding = false; + + blendMethod = BlendMethod::Normal; + renderFlag = RenderUpdateFlag::None; + ctxFlag = ContextFlag::Default; + opacity = 255; + paint->id = 0; + } + + bool rotate(float degree) + { + if (tr.overriding) return false; + if (tvg::equal(degree, tr.degree)) return true; + tr.degree = degree; + renderFlag |= RenderUpdateFlag::Transform; + + return true; + } + + bool scale(float factor) + { + if (tr.overriding) return false; + if (tvg::equal(factor, tr.scale)) return true; + tr.scale = factor; + renderFlag |= RenderUpdateFlag::Transform; + + return true; + } + + bool translate(float x, float y) + { + if (tr.overriding) return false; + if (tvg::equal(x, tr.m.e13) && tvg::equal(y, tr.m.e23)) return true; + tr.m.e13 = x; + tr.m.e23 = y; + renderFlag |= RenderUpdateFlag::Transform; + + return true; + } + + void blend(BlendMethod method) + { + if (blendMethod != method) { + blendMethod = method; + renderFlag |= RenderUpdateFlag::Blend; + } + } + RenderRegion bounds(RenderMethod* renderer) const; Iterator* iterator(); - bool rotate(float degree); - bool scale(float factor); - bool translate(float x, float y); bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking, bool origin = false); RenderData update(RenderMethod* renderer, const Matrix& pm, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false); bool render(RenderMethod* renderer); Paint* duplicate(Paint* ret = nullptr); - void reset(); }; } diff --git a/src/renderer/tvgPicture.cpp b/src/renderer/tvgPicture.cpp index ff370850..8c66cc14 100644 --- a/src/renderer/tvgPicture.cpp +++ b/src/renderer/tvgPicture.cpp @@ -23,124 +23,9 @@ #include "tvgPaint.h" #include "tvgPicture.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -RenderUpdateFlag Picture::Impl::load() +Picture::Picture() { - if (loader) { - if (paint) { - loader->sync(); - } else { - paint = loader->paint(); - if (paint) { - if (w != loader->w || h != loader->h) { - if (!resizing) { - w = loader->w; - h = loader->h; - } - loader->resize(paint, w, h); - resizing = false; - } - return RenderUpdateFlag::None; - } - } - if (!surface) { - if ((surface = loader->bitmap())) { - return RenderUpdateFlag::Image; - } - } - } - return RenderUpdateFlag::None; -} - - -void Picture::Impl::queryComposition(uint8_t opacity) -{ - cFlag = CompositionFlag::Invalid; - - //In this case, paint(scene) would try composition itself. - if (opacity < 255) return; - - //Composition test - const Paint* target; - picture->mask(&target); - if (!target || target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return; - cFlag = CompositionFlag::Opacity; -} - - -bool Picture::Impl::render(RenderMethod* renderer) -{ - bool ret = false; - renderer->blend(PP(picture)->blendMethod); - - if (surface) return renderer->renderImage(rd); - else if (paint) { - RenderCompositor* cmp = nullptr; - if (cFlag) { - cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(cFlag)); - renderer->beginComposite(cmp, MaskMethod::None, 255); - } - ret = paint->pImpl->render(renderer); - if (cmp) renderer->endComposite(cmp); - } - return ret; -} - - -bool Picture::Impl::size(float w, float h) -{ - this->w = w; - this->h = h; - resizing = true; - return true; -} - - -RenderRegion Picture::Impl::bounds(RenderMethod* renderer) -{ - if (rd) return renderer->region(rd); - if (paint) return paint->pImpl->bounds(renderer); - return {0, 0, 0, 0}; -} - - -Result Picture::Impl::load(ImageLoader* loader) -{ - //Same resource has been loaded. - if (this->loader == loader) { - this->loader->sharing--; //make it sure the reference counting. - return Result::Success; - } else if (this->loader) { - LoaderMgr::retrieve(this->loader); - } - - this->loader = loader; - - if (!loader->read()) return Result::Unknown; - - this->w = loader->w; - this->h = loader->h; - - return Result::Success; -} - - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -Picture::Picture() : pImpl(new Impl(this)) -{ -} - - -Picture::~Picture() -{ - delete(pImpl); + pImpl = new Impl(this); } @@ -160,8 +45,7 @@ Result Picture::load(const char* filename) noexcept { #ifdef THORVG_FILE_IO_SUPPORT if (!filename) return Result::InvalidArguments; - - return pImpl->load(filename); + return PICTURE(this)->load(filename); #else TVGLOG("RENDERER", "FILE IO is disabled!"); return Result::NonSupport; @@ -171,33 +55,26 @@ Result Picture::load(const char* filename) noexcept Result Picture::load(const char* data, uint32_t size, const char* mimeType, const char* rpath, bool copy) noexcept { - if (!data || size <= 0) return Result::InvalidArguments; - - return pImpl->load(data, size, mimeType, rpath, copy); + return PICTURE(this)->load(data, size, mimeType, rpath, copy); } Result Picture::load(uint32_t* data, uint32_t w, uint32_t h, ColorSpace cs, bool copy) noexcept { - if (!data || w <= 0 || h <= 0 || cs == ColorSpace::Unknown) return Result::InvalidArguments; - - return pImpl->load(data, w, h, cs, copy); + return PICTURE(this)->load(data, w, h, cs, copy); } Result Picture::size(float w, float h) noexcept { - if (pImpl->size(w, h)) return Result::Success; - return Result::InsufficientCondition; + PICTURE(this)->size(w, h); + return Result::Success; } Result Picture::size(float* w, float* h) const noexcept { - if (!pImpl->loader) return Result::InsufficientCondition; - if (w) *w = pImpl->w; - if (h) *h = pImpl->h; - return Result::Success; + return PICTURE(this)->size(w, h); } diff --git a/src/renderer/tvgPicture.h b/src/renderer/tvgPicture.h index 64124d6f..daabe7ce 100644 --- a/src/renderer/tvgPicture.h +++ b/src/renderer/tvgPicture.h @@ -23,10 +23,10 @@ #ifndef _TVG_PICTURE_H_ #define _TVG_PICTURE_H_ -#include #include "tvgPaint.h" #include "tvgLoader.h" +#define PICTURE(A) PIMPL(A, Picture) struct PictureIterator : Iterator { @@ -55,44 +55,32 @@ struct PictureIterator : Iterator }; -struct Picture::Impl +struct Picture::Impl : Paint::Impl { ImageLoader* loader = nullptr; - - Paint* paint = nullptr; //vector picture uses - RenderSurface* surface = nullptr; //bitmap picture uses - RenderData rd = nullptr; //engine data + Paint* vector = nullptr; //vector picture uses + RenderSurface* bitmap = nullptr; //bitmap picture uses + RenderData rd = nullptr; float w = 0, h = 0; - Picture* picture = nullptr; - uint8_t cFlag = CompositionFlag::Invalid; + uint8_t compFlag = CompositionFlag::Invalid; bool resizing = false; - void queryComposition(uint8_t opacity); - bool render(RenderMethod* renderer); - bool size(float w, float h); - RenderRegion bounds(RenderMethod* renderer); - Result load(ImageLoader* ploader); - - Impl(Picture* p) : picture(p) + Impl(Picture* p) : Paint::Impl(p) { } ~Impl() { LoaderMgr::retrieve(loader); - if (surface) { - if (auto renderer = PP(picture)->renderer) { - renderer->dispose(rd); - } - } - delete(paint); + if (bitmap && renderer) renderer->dispose(rd); + delete(vector); } RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper) { auto flag = static_cast(pFlag | load()); - if (surface) { + if (bitmap) { if (flag == RenderUpdateFlag::None) return rd; //Overriding Transformation by the desired image size @@ -101,18 +89,34 @@ struct Picture::Impl auto scale = sx < sy ? sx : sy; auto m = transform * Matrix{scale, 0, 0, 0, scale, 0, 0, 0, 1}; - rd = renderer->prepare(surface, rd, m, clips, opacity, flag); - } else if (paint) { + rd = renderer->prepare(bitmap, rd, m, clips, opacity, flag); + } else if (vector) { if (resizing) { - loader->resize(paint, w, h); + loader->resize(vector, w, h); resizing = false; } queryComposition(opacity); - rd = paint->pImpl->update(renderer, transform, clips, opacity, flag, false); + rd = vector->pImpl->update(renderer, transform, clips, opacity, flag, false); } return rd; } + void size(float w, float h) + { + this->w = w; + this->h = h; + resizing = true; + } + + Result size(float* w, float* h) const + { + if (!loader) return Result::InsufficientCondition; + if (w) *w = this->w; + if (h) *h = this->h; + return Result::Success; + } + + bool bounds(float* x, float* y, float* w, float* h, bool stroking) { if (x) *x = 0; @@ -124,7 +128,7 @@ struct Picture::Impl Result load(const char* filename) { - if (paint || surface) return Result::InsufficientCondition; + if (vector || bitmap) return Result::InsufficientCondition; bool invalid; //Invalid Path auto loader = static_cast(LoaderMgr::loader(filename, &invalid)); @@ -137,7 +141,8 @@ struct Picture::Impl Result load(const char* data, uint32_t size, const char* mimeType, const char* rpath, bool copy) { - if (paint || surface) return Result::InsufficientCondition; + if (!data || size <= 0) return Result::InvalidArguments; + if (vector || bitmap) return Result::InsufficientCondition; auto loader = static_cast(LoaderMgr::loader(data, size, mimeType, rpath, copy)); if (!loader) return Result::NonSupport; return load(loader); @@ -145,7 +150,8 @@ struct Picture::Impl Result load(uint32_t* data, uint32_t w, uint32_t h, ColorSpace cs, bool copy) { - if (paint || surface) return Result::InsufficientCondition; + if (!data || w <= 0 || h <= 0 || cs == ColorSpace::Unknown) return Result::InvalidArguments; + if (vector || bitmap) return Result::InsufficientCondition; auto loader = static_cast(LoaderMgr::loader(data, w, h, cs, copy)); if (!loader) return Result::FailedAllocation; @@ -160,17 +166,17 @@ struct Picture::Impl load(); auto picture = Picture::gen(); - auto dup = picture->pImpl; + auto dup = PICTURE(picture); - if (paint) dup->paint = paint->duplicate(); + if (vector) dup->vector = vector->duplicate(); if (loader) { dup->loader = loader; ++dup->loader->sharing; - PP(picture)->renderFlag |= RenderUpdateFlag::Image; + PAINT(picture)->renderFlag |= RenderUpdateFlag::Image; } - dup->surface = surface; + dup->bitmap = bitmap; dup->w = w; dup->h = h; dup->resizing = resizing; @@ -181,7 +187,7 @@ struct Picture::Impl Iterator* iterator() { load(); - return new PictureIterator(paint); + return new PictureIterator(vector); } uint32_t* data(uint32_t* w, uint32_t* h) @@ -196,11 +202,96 @@ struct Picture::Impl if (w) *w = 0; if (h) *h = 0; } - if (surface) return surface->buf32; + if (bitmap) return bitmap->buf32; else return nullptr; } - RenderUpdateFlag load(); + RenderUpdateFlag load() + { + if (loader) { + if (vector) { + loader->sync(); + } else { + vector = loader->paint(); + if (vector) { + if (w != loader->w || h != loader->h) { + if (!resizing) { + w = loader->w; + h = loader->h; + } + loader->resize(vector, w, h); + resizing = false; + } + return RenderUpdateFlag::None; + } + } + if (!bitmap) { + if ((bitmap = loader->bitmap())) { + return RenderUpdateFlag::Image; + } + } + } + return RenderUpdateFlag::None; + } + + void queryComposition(uint8_t opacity) + { + compFlag = CompositionFlag::Invalid; + + //In this case, paint(scene) would try composition itself. + if (opacity < 255) return; + + //Composition test + const Paint* target; + paint->mask(&target); + if (!target || target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return; + compFlag = CompositionFlag::Opacity; + } + + bool render(RenderMethod* renderer) + { + bool ret = false; + renderer->blend(blendMethod); + + if (bitmap) return renderer->renderImage(rd); + else if (vector) { + RenderCompositor* cmp = nullptr; + if (compFlag) { + cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(compFlag)); + renderer->beginComposite(cmp, MaskMethod::None, 255); + } + ret = vector->pImpl->render(renderer); + if (cmp) renderer->endComposite(cmp); + } + return ret; + } + + RenderRegion bounds(RenderMethod* renderer) + { + if (rd) return renderer->region(rd); + if (vector) return vector->pImpl->bounds(renderer); + return {0, 0, 0, 0}; + } + + Result load(ImageLoader* loader) + { + //Same resource has been loaded. + if (this->loader == loader) { + this->loader->sharing--; //make it sure the reference counting. + return Result::Success; + } else if (this->loader) { + LoaderMgr::retrieve(this->loader); + } + + this->loader = loader; + + if (!loader->read()) return Result::Unknown; + + this->w = loader->w; + this->h = loader->h; + + return Result::Success; + } }; #endif //_TVG_PICTURE_H_ diff --git a/src/renderer/tvgRender.cpp b/src/renderer/tvgRender.cpp index 0ad85031..97b8a400 100644 --- a/src/renderer/tvgRender.cpp +++ b/src/renderer/tvgRender.cpp @@ -23,14 +23,6 @@ #include "tvgMath.h" #include "tvgRender.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ uint32_t RenderMethod::ref() { diff --git a/src/renderer/tvgScene.cpp b/src/renderer/tvgScene.cpp index 4072cbaa..e5cf51dd 100644 --- a/src/renderer/tvgScene.cpp +++ b/src/renderer/tvgScene.cpp @@ -20,38 +20,12 @@ * SOFTWARE. */ -#include #include "tvgScene.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ -Result Scene::Impl::resetEffects() +Scene::Scene() { - if (effects) { - for (auto e = effects->begin(); e < effects->end(); ++e) { - delete(*e); - } - delete(effects); - effects = nullptr; - } - return Result::Success; -} - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -Scene::Scene() : pImpl(new Impl(this)) -{ -} - - -Scene::~Scene() -{ - delete(pImpl); + pImpl = new Impl(this); } @@ -69,56 +43,27 @@ Type Scene::type() const noexcept Result Scene::push(Paint* target, Paint* at) noexcept { - if (!target) return Result::InvalidArguments; - target->ref(); - - return pImpl->insert(target, at); + return SCENE(this)->insert(target, at); } Result Scene::remove(Paint* paint) noexcept { - if (paint) return pImpl->remove(paint); - else return pImpl->clearPaints(); + if (paint) return SCENE(this)->remove(paint); + else return SCENE(this)->clearPaints(); } const list& Scene::paints() const noexcept { - return pImpl->paints; + return SCENE(this)->paints; } Result Scene::push(SceneEffect effect, ...) noexcept { - if (effect == SceneEffect::ClearAll) return pImpl->resetEffects(); - - if (!pImpl->effects) pImpl->effects = new Array; - va_list args; va_start(args, effect); - RenderEffect* re = nullptr; - - switch (effect) { - case SceneEffect::GaussianBlur: { - re = RenderEffectGaussianBlur::gen(args); - break; - } - case SceneEffect::DropShadow: { - re = RenderEffectDropShadow::gen(args); - break; - } - case SceneEffect::Fill: { - re = RenderEffectFill::gen(args); - break; - } - default: break; - } - - if (!re) return Result::InvalidArguments; - - pImpl->effects->push(re); - - return Result::Success; + return SCENE(this)->push(effect, args); } diff --git a/src/renderer/tvgScene.h b/src/renderer/tvgScene.h index 279801e2..626bd755 100644 --- a/src/renderer/tvgScene.h +++ b/src/renderer/tvgScene.h @@ -24,9 +24,12 @@ #define _TVG_SCENE_H_ #include +#include #include "tvgMath.h" #include "tvgPaint.h" +#define SCENE(A) PIMPL(A, Scene) + struct SceneIterator : Iterator { list* paints; @@ -56,17 +59,16 @@ struct SceneIterator : Iterator } }; -struct Scene::Impl +struct Scene::Impl : Paint::Impl { - list paints; + list paints; //children list RenderData rd = nullptr; - Scene* scene = nullptr; RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX}; Array* effects = nullptr; uint8_t compFlag = CompositionFlag::Invalid; uint8_t opacity; //for composition - Impl(Scene* s) : scene(s) + Impl(Scene* s) : Paint::Impl(s) { } @@ -76,9 +78,7 @@ struct Scene::Impl clearPaints(); - if (auto renderer = PP(scene)->renderer) { - renderer->dispose(rd); - } + if (renderer) renderer->dispose(rd); } uint8_t needComposition(uint8_t opacity) @@ -89,8 +89,8 @@ struct Scene::Impl //post effects, masking, blending may require composition if (effects) compFlag |= CompositionFlag::PostProcessing; - if (scene->mask(nullptr) != MaskMethod::None) compFlag |= CompositionFlag::Masking; - if (PP(scene)->blendMethod != BlendMethod::Normal) compFlag |= CompositionFlag::Blending; + if (paint->mask(nullptr) != MaskMethod::None) compFlag |= CompositionFlag::Masking; + if (blendMethod != BlendMethod::Normal) compFlag |= CompositionFlag::Blending; //Half translucent requires intermediate composition. if (opacity == 255) return compFlag; @@ -127,7 +127,7 @@ struct Scene::Impl RenderCompositor* cmp = nullptr; auto ret = true; - renderer->blend(PP(scene)->blendMethod); + renderer->blend(blendMethod); if (compFlag) { cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(compFlag)); @@ -206,7 +206,7 @@ struct Scene::Impl auto w = 0.0f; auto h = 0.0f; - if (!P(paint)->bounds(&x, &y, &w, &h, true, stroking)) continue; + if (!PAINT(paint)->bounds(&x, &y, &w, &h, true, stroking)) continue; //Merge regions if (x < x1) x1 = x; @@ -228,7 +228,7 @@ struct Scene::Impl if (ret) TVGERR("RENDERER", "TODO: duplicate()"); auto scene = Scene::gen(); - auto dup = scene->pImpl; + auto dup = SCENE(scene); for (auto paint : paints) { auto cdup = paint->duplicate(); @@ -265,14 +265,17 @@ struct Scene::Impl for (auto p : paints) { if (p == paint) return; } - TVGERR("RENDERER", "The paint(%p) is not existed from the scene(%p)", paint, scene); + TVGERR("RENDERER", "The paint(%p) is not existed from the scene(%p)", paint, this->paint); #endif } Result insert(Paint* target, Paint* at) { + if (!target) return Result::InvalidArguments; + target->ref(); + //Relocated the paint to the current scene space - P(target)->renderFlag |= RenderUpdateFlag::Transform; + PAINT(target)->renderFlag |= RenderUpdateFlag::Transform; if (at == nullptr) { paints.push_back(target); @@ -290,7 +293,48 @@ struct Scene::Impl return new SceneIterator(&paints); } - Result resetEffects(); + Result resetEffects() + { + if (effects) { + for (auto e = effects->begin(); e < effects->end(); ++e) { + delete(*e); + } + delete(effects); + effects = nullptr; + } + return Result::Success; + } + + Result push(SceneEffect effect, va_list& args) + { + if (effect == SceneEffect::ClearAll) return resetEffects(); + + if (!this->effects) this->effects = new Array; + + RenderEffect* re = nullptr; + + switch (effect) { + case SceneEffect::GaussianBlur: { + re = RenderEffectGaussianBlur::gen(args); + break; + } + case SceneEffect::DropShadow: { + re = RenderEffectDropShadow::gen(args); + break; + } + case SceneEffect::Fill: { + re = RenderEffectFill::gen(args); + break; + } + default: break; + } + + if (!re) return Result::InvalidArguments; + + this->effects->push(re); + + return Result::Success; + } }; #endif //_TVG_SCENE_H_ diff --git a/src/renderer/tvgShape.cpp b/src/renderer/tvgShape.cpp index a1d4c34d..de42d9fd 100644 --- a/src/renderer/tvgShape.cpp +++ b/src/renderer/tvgShape.cpp @@ -23,23 +23,10 @@ #include "tvgMath.h" #include "tvgShape.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -Shape :: Shape() : pImpl(new Impl(this)) +Shape :: Shape() { -} - - -Shape :: ~Shape() -{ - delete(pImpl); + pImpl = new Impl(this); } @@ -57,301 +44,210 @@ Type Shape::type() const noexcept Result Shape::reset() noexcept { - pImpl->rs.path.cmds.clear(); - pImpl->rs.path.pts.clear(); - - pImpl->rFlag |= RenderUpdateFlag::Path; - + SHAPE(this)->resetPath(); return Result::Success; } uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept { - if (cmds) *cmds = pImpl->rs.path.cmds.data; - return pImpl->rs.path.cmds.count; + if (cmds) *cmds = SHAPE(this)->rs.path.cmds.data; + return SHAPE(this)->rs.path.cmds.count; } uint32_t Shape::pathCoords(const Point** pts) const noexcept { - if (pts) *pts = pImpl->rs.path.pts.data; - return pImpl->rs.path.pts.count; + if (pts) *pts = SHAPE(this)->rs.path.pts.data; + return SHAPE(this)->rs.path.pts.count; } Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept { - if (cmdCnt == 0 || ptsCnt == 0 || !cmds || !pts) return Result::InvalidArguments; - - pImpl->grow(cmdCnt, ptsCnt); - pImpl->append(cmds, cmdCnt, pts, ptsCnt); - - pImpl->rFlag |= RenderUpdateFlag::Path; - - return Result::Success; + return SHAPE(this)->appendPath(cmds, cmdCnt, pts, ptsCnt); } Result Shape::moveTo(float x, float y) noexcept { - pImpl->moveTo(x, y); - + SHAPE(this)->moveTo(x, y); return Result::Success; } Result Shape::lineTo(float x, float y) noexcept { - pImpl->lineTo(x, y); - - pImpl->rFlag |= RenderUpdateFlag::Path; - + SHAPE(this)->lineTo(x, y); return Result::Success; } Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { - pImpl->cubicTo(cx1, cy1, cx2, cy2, x, y); - - pImpl->rFlag |= RenderUpdateFlag::Path; - + SHAPE(this)->cubicTo(cx1, cy1, cx2, cy2, x, y); return Result::Success; } Result Shape::close() noexcept { - pImpl->close(); - - pImpl->rFlag |= RenderUpdateFlag::Path; - + SHAPE(this)->close(); return Result::Success; } Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept { - auto rxKappa = rx * PATH_KAPPA; - auto ryKappa = ry * PATH_KAPPA; - - pImpl->grow(6, 13); - pImpl->moveTo(cx + rx, cy); - pImpl->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry); - pImpl->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy); - pImpl->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry); - pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); - pImpl->close(); - - pImpl->rFlag |= RenderUpdateFlag::Path; - + SHAPE(this)->appendCircle(cx, cy, rx, ry); return Result::Success; } Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) noexcept { - auto halfW = w * 0.5f; - auto halfH = h * 0.5f; - - //clamping cornerRadius by minimum size - if (rx > halfW) rx = halfW; - if (ry > halfH) ry = halfH; - - //rectangle - if (rx == 0 && ry == 0) { - pImpl->grow(5, 4); - pImpl->moveTo(x, y); - pImpl->lineTo(x + w, y); - pImpl->lineTo(x + w, y + h); - pImpl->lineTo(x, y + h); - pImpl->close(); - //rounded rectangle or circle - } else { - auto hrx = rx * PATH_KAPPA; - auto hry = ry * PATH_KAPPA; - pImpl->grow(10, 17); - pImpl->moveTo(x + rx, y); - pImpl->lineTo(x + w - rx, y); - pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry); - pImpl->lineTo(x + w, y + h - ry); - pImpl->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h); - pImpl->lineTo(x + rx, y + h); - pImpl->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry); - pImpl->lineTo(x, y + ry); - pImpl->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y); - pImpl->close(); - } - - pImpl->rFlag |= RenderUpdateFlag::Path; - + SHAPE(this)->appendRect(x, y, w, h, rx, ry); return Result::Success; } Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { - if (pImpl->rs.fill) { - delete(pImpl->rs.fill); - pImpl->rs.fill = nullptr; - pImpl->rFlag |= RenderUpdateFlag::Gradient; - } - - if (r == pImpl->rs.color.r && g == pImpl->rs.color.g && b == pImpl->rs.color.b && a == pImpl->rs.color.a) return Result::Success; - - pImpl->rs.color = {r, g, b, a}; - - pImpl->rFlag |= RenderUpdateFlag::Color; - + SHAPE(this)->fill(r, g, b, a); return Result::Success; } Result Shape::fill(Fill* f) noexcept { - if (!f) return Result::InvalidArguments; - - if (pImpl->rs.fill && pImpl->rs.fill != f) delete(pImpl->rs.fill); - pImpl->rs.fill = f; - pImpl->rFlag |= RenderUpdateFlag::Gradient; - - return Result::Success; + return SHAPE(this)->fill(f); } Result Shape::fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { - pImpl->rs.fillColor(r, g, b, a); - + SHAPE(this)->rs.fillColor(r, g, b, a); return Result::Success; } const Fill* Shape::fill() const noexcept { - return pImpl->rs.fill; + return SHAPE(this)->rs.fill; } Result Shape::order(bool strokeFirst) noexcept { - pImpl->strokeFirst(strokeFirst); + SHAPE(this)->strokeFirst(strokeFirst); return Result::Success; } Result Shape::strokeWidth(float width) noexcept { - pImpl->strokeWidth(width); + SHAPE(this)->strokeWidth(width); return Result::Success; } float Shape::strokeWidth() const noexcept { - return pImpl->rs.strokeWidth(); + return SHAPE(this)->rs.strokeWidth(); } Result Shape::strokeFill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { - pImpl->strokeFill(r, g, b, a); + SHAPE(this)->strokeFill(r, g, b, a); return Result::Success; } Result Shape::strokeFill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { - if (!pImpl->rs.strokeFill(r, g, b, a)) return Result::InsufficientCondition; - + if (!SHAPE(this)->rs.strokeFill(r, g, b, a)) return Result::InsufficientCondition; return Result::Success; } Result Shape::strokeFill(Fill* f) noexcept { - return pImpl->strokeFill(f); + return SHAPE(this)->strokeFill(f); } const Fill* Shape::strokeFill() const noexcept { - return pImpl->rs.strokeFill(); + return SHAPE(this)->rs.strokeFill(); } Result Shape::strokeDash(const float* dashPattern, uint32_t cnt, float offset) noexcept { - return pImpl->strokeDash(dashPattern, cnt, offset); + return SHAPE(this)->strokeDash(dashPattern, cnt, offset); } uint32_t Shape::strokeDash(const float** dashPattern, float* offset) const noexcept { - return pImpl->rs.strokeDash(dashPattern, offset); + return SHAPE(this)->rs.strokeDash(dashPattern, offset); } Result Shape::strokeCap(StrokeCap cap) noexcept { - pImpl->strokeCap(cap); + SHAPE(this)->strokeCap(cap); return Result::Success; } Result Shape::strokeJoin(StrokeJoin join) noexcept { - pImpl->strokeJoin(join); + SHAPE(this)->strokeJoin(join); return Result::Success; } Result Shape::strokeMiterlimit(float miterlimit) noexcept { - // https://www.w3.org/TR/SVG2/painting.html#LineJoin - // - A negative value for stroke-miterlimit must be treated as an illegal value. - if (miterlimit < 0.0f) return Result::InvalidArguments; - // TODO Find out a reasonable max value. - pImpl->strokeMiterlimit(miterlimit); - return Result::Success; + return SHAPE(this)->strokeMiterlimit(miterlimit); } StrokeCap Shape::strokeCap() const noexcept { - return pImpl->rs.strokeCap(); + return SHAPE(this)->rs.strokeCap(); } StrokeJoin Shape::strokeJoin() const noexcept { - return pImpl->rs.strokeJoin(); + return SHAPE(this)->rs.strokeJoin(); } float Shape::strokeMiterlimit() const noexcept { - return pImpl->rs.strokeMiterlimit(); + return SHAPE(this)->rs.strokeMiterlimit(); } Result Shape::strokeTrim(float begin, float end, bool simultaneous) noexcept { - pImpl->strokeTrim(begin, end, simultaneous); + SHAPE(this)->strokeTrim(begin, end, simultaneous); return Result::Success; } Result Shape::fill(FillRule r) noexcept { - pImpl->rs.rule = r; - + SHAPE(this)->rs.rule = r; return Result::Success; } FillRule Shape::fillRule() const noexcept { - return pImpl->rs.rule; + return SHAPE(this)->rs.rule; } diff --git a/src/renderer/tvgShape.h b/src/renderer/tvgShape.h index 72e5f7c8..bcdac7eb 100644 --- a/src/renderer/tvgShape.h +++ b/src/renderer/tvgShape.h @@ -27,25 +27,22 @@ #include "tvgMath.h" #include "tvgPaint.h" +#define SHAPE(A) PIMPL(A, Shape) -struct Shape::Impl +struct Shape::Impl : Paint::Impl { - RenderShape rs; //shape data - RenderData rd = nullptr; //engine data - Shape* shape; - uint8_t rFlag = RenderUpdateFlag::None; - uint8_t cFlag = CompositionFlag::Invalid; - uint8_t opacity; //for composition + RenderShape rs; + RenderData rd = nullptr; + uint8_t compFlag = CompositionFlag::Invalid; + uint8_t opacity; //for composition - Impl(Shape* s) : shape(s) + Impl(Shape* s) : Paint::Impl(s) { } ~Impl() { - if (auto renderer = PP(shape)->renderer) { - renderer->dispose(rd); - } + if (renderer) renderer->dispose(rd); } bool render(RenderMethod* renderer) @@ -54,10 +51,10 @@ struct Shape::Impl RenderCompositor* cmp = nullptr; - renderer->blend(PP(shape)->blendMethod); + renderer->blend(blendMethod); - if (cFlag) { - cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(cFlag)); + if (compFlag) { + cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(compFlag)); renderer->beginComposite(cmp, MaskMethod::None, opacity); } @@ -68,7 +65,7 @@ struct Shape::Impl bool needComposition(uint8_t opacity) { - cFlag = CompositionFlag::Invalid; + compFlag = CompositionFlag::Invalid; if (opacity == 0) return false; @@ -78,13 +75,13 @@ struct Shape::Impl //translucent fill & stroke if (opacity < 255) { - cFlag = CompositionFlag::Opacity; + compFlag = CompositionFlag::Opacity; return true; } //Composition test const Paint* target; - auto method = shape->mask(&target); + auto method = paint->mask(&target); if (!target) return false; if ((target->pImpl->opacity == 255 || target->pImpl->opacity == 0) && target->type() == Type::Shape) { @@ -100,13 +97,13 @@ struct Shape::Impl } } - cFlag = CompositionFlag::Masking; + compFlag = CompositionFlag::Masking; return true; } RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) { - if (static_cast(pFlag | rFlag) == RenderUpdateFlag::None) return rd; + if (static_cast(pFlag | renderFlag) == RenderUpdateFlag::None) return rd; if (needComposition(opacity)) { /* Overriding opacity value. If this scene is half-translucent, @@ -115,8 +112,7 @@ struct Shape::Impl opacity = 255; } - rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast(pFlag | rFlag), clipper); - rFlag = RenderUpdateFlag::None; + rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast(pFlag | renderFlag), clipper); return rd; } @@ -191,6 +187,7 @@ struct Shape::Impl { rs.path.cmds.push(PathCommand::LineTo); rs.path.pts.push({x, y}); + renderFlag |= RenderUpdateFlag::Path; } void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) @@ -199,21 +196,23 @@ struct Shape::Impl rs.path.pts.push({cx1, cy1}); rs.path.pts.push({cx2, cy2}); rs.path.pts.push({x, y}); + + renderFlag |= RenderUpdateFlag::Path; } void close() { //Don't close multiple times. if (rs.path.cmds.count > 0 && rs.path.cmds.last() == PathCommand::Close) return; - rs.path.cmds.push(PathCommand::Close); + renderFlag |= RenderUpdateFlag::Path; } void strokeWidth(float width) { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->width = width; - rFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::Stroke; } void strokeTrim(float begin, float end, bool simultaneous) @@ -223,13 +222,12 @@ struct Shape::Impl rs.stroke = new RenderStroke(); } - if (tvg::equal(rs.stroke->trim.begin, begin) && tvg::equal(rs.stroke->trim.end, end) && - rs.stroke->trim.simultaneous == simultaneous) return; + if (tvg::equal(rs.stroke->trim.begin, begin) && tvg::equal(rs.stroke->trim.end, end) && rs.stroke->trim.simultaneous == simultaneous) return; rs.stroke->trim.begin = begin; rs.stroke->trim.end = end; rs.stroke->trim.simultaneous = simultaneous; - rFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::Stroke; } bool strokeTrim(float* begin, float* end) @@ -249,21 +247,26 @@ struct Shape::Impl { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->cap = cap; - rFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::Stroke; } void strokeJoin(StrokeJoin join) { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->join = join; - rFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::Stroke; } - void strokeMiterlimit(float miterlimit) + Result strokeMiterlimit(float miterlimit) { + // https://www.w3.org/TR/SVG2/painting.html#LineJoin + // - A negative value for stroke-miterlimit must be treated as an illegal value. + if (miterlimit < 0.0f) return Result::InvalidArguments; if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->miterlimit = miterlimit; - rFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::Stroke; + + return Result::Success; } void strokeFill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) @@ -272,12 +275,12 @@ struct Shape::Impl if (rs.stroke->fill) { delete(rs.stroke->fill); rs.stroke->fill = nullptr; - rFlag |= RenderUpdateFlag::GradientStroke; + renderFlag |= RenderUpdateFlag::GradientStroke; } rs.stroke->color = {r, g, b, a}; - rFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::Stroke; } Result strokeFill(Fill* f) @@ -289,8 +292,8 @@ struct Shape::Impl rs.stroke->fill = f; rs.stroke->color.a = 0; - rFlag |= RenderUpdateFlag::Stroke; - rFlag |= RenderUpdateFlag::GradientStroke; + renderFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::GradientStroke; return Result::Success; } @@ -325,7 +328,7 @@ struct Shape::Impl } rs.stroke->dashCnt = cnt; rs.stroke->dashOffset = offset; - rFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::Stroke; return Result::Success; } @@ -340,12 +343,99 @@ struct Shape::Impl { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->strokeFirst = strokeFirst; - rFlag |= RenderUpdateFlag::Stroke; + renderFlag |= RenderUpdateFlag::Stroke; } - void update(RenderUpdateFlag flag) + Result fill(Fill* f) { - rFlag |= flag; + if (!f) return Result::InvalidArguments; + + if (rs.fill && rs.fill != f) delete(rs.fill); + rs.fill = f; + renderFlag |= RenderUpdateFlag::Gradient; + + return Result::Success; + } + + void fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) + { + if (rs.fill) { + delete(rs.fill); + rs.fill = nullptr; + renderFlag |= RenderUpdateFlag::Gradient; + } + + if (r == rs.color.r && g == rs.color.g && b == rs.color.b && a == rs.color.a) return; + + rs.color = {r, g, b, a}; + renderFlag |= RenderUpdateFlag::Color; + } + + void resetPath() + { + rs.path.cmds.clear(); + rs.path.pts.clear(); + renderFlag |= RenderUpdateFlag::Path; + } + + Result appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) + { + if (cmdCnt == 0 || ptsCnt == 0 || !cmds || !pts) return Result::InvalidArguments; + + grow(cmdCnt, ptsCnt); + append(cmds, cmdCnt, pts, ptsCnt); + renderFlag |= RenderUpdateFlag::Path; + + return Result::Success; + } + + void appendCircle(float cx, float cy, float rx, float ry) + { + auto rxKappa = rx * PATH_KAPPA; + auto ryKappa = ry * PATH_KAPPA; + + grow(6, 13); + moveTo(cx + rx, cy); + cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry); + cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy); + cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry); + cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); + close(); + } + + void appendRect(float x, float y, float w, float h, float rx, float ry) + { + auto halfW = w * 0.5f; + auto halfH = h * 0.5f; + + //clamping cornerRadius by minimum size + if (rx > halfW) rx = halfW; + if (ry > halfH) ry = halfH; + + //rectangle + if (rx == 0 && ry == 0) { + grow(5, 4); + moveTo(x, y); + lineTo(x + w, y); + lineTo(x + w, y + h); + lineTo(x, y + h); + close(); + //rounded rectangle or circle + } else { + auto hrx = rx * PATH_KAPPA; + auto hry = ry * PATH_KAPPA; + grow(10, 17); + moveTo(x + rx, y); + lineTo(x + w - rx, y); + cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry); + lineTo(x + w, y + h - ry); + cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h); + lineTo(x + rx, y + h); + cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry); + lineTo(x, y + ry); + cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y); + close(); + } } Paint* duplicate(Paint* ret) @@ -354,11 +444,11 @@ struct Shape::Impl if (shape) shape->reset(); else shape = Shape::gen(); - auto dup = shape->pImpl; + auto dup = SHAPE(shape); delete(dup->rs.fill); //Default Properties - dup->rFlag = RenderUpdateFlag::All; + dup->renderFlag = RenderUpdateFlag::All; dup->rs.rule = rs.rule; dup->rs.color = rs.color; @@ -384,7 +474,7 @@ struct Shape::Impl void reset() { - PP(shape)->reset(); + PAINT(paint)->reset(); rs.path.cmds.clear(); rs.path.pts.clear(); diff --git a/src/renderer/tvgSwCanvas.cpp b/src/renderer/tvgSwCanvas.cpp index 334fc4d9..8236ba51 100644 --- a/src/renderer/tvgSwCanvas.cpp +++ b/src/renderer/tvgSwCanvas.cpp @@ -25,38 +25,21 @@ #ifdef THORVG_SW_RASTER_SUPPORT #include "tvgSwRenderer.h" -#else - class SwRenderer : public RenderMethod - { - //Non Supported. Dummy Class */ - }; #endif -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ -struct SwCanvas::Impl +SwCanvas::SwCanvas() { -}; - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - #ifdef THORVG_SW_RASTER_SUPPORT -SwCanvas::SwCanvas() : Canvas(SwRenderer::gen()), pImpl(nullptr) -#else -SwCanvas::SwCanvas() : Canvas(nullptr), pImpl(nullptr) + pImpl->renderer = SwRenderer::gen(); + pImpl->renderer->ref(); #endif -{ } SwCanvas::~SwCanvas() { - delete(pImpl); + //TODO: } @@ -64,11 +47,11 @@ Result SwCanvas::mempool(MempoolPolicy policy) noexcept { #ifdef THORVG_SW_RASTER_SUPPORT //We know renderer type, avoid dynamic_cast for performance. - auto renderer = static_cast(Canvas::pImpl->renderer); + auto renderer = static_cast(pImpl->renderer); if (!renderer) return Result::MemoryCorruption; //It can't change the policy during the running. - if (!Canvas::pImpl->scene->paints().empty()) return Result::InsufficientCondition; + if (!pImpl->scene->paints().empty()) return Result::InsufficientCondition; if (policy == MempoolPolicy::Individual) renderer->mempool(false); else renderer->mempool(true); @@ -85,23 +68,23 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t if (cs == ColorSpace::Unknown) return Result::InvalidArguments; if (cs == ColorSpace::Grayscale8) return Result::NonSupport; - if (Canvas::pImpl->status != Status::Damaged && Canvas::pImpl->status != Status::Synced) { + if (pImpl->status != Status::Damaged && pImpl->status != Status::Synced) { return Result::InsufficientCondition; } //We know renderer type, avoid dynamic_cast for performance. - auto renderer = static_cast(Canvas::pImpl->renderer); + auto renderer = static_cast(pImpl->renderer); if (!renderer) return Result::MemoryCorruption; if (!renderer->target(buffer, stride, w, h, static_cast(cs))) return Result::InvalidArguments; - Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; - renderer->viewport(Canvas::pImpl->vport); + pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; + renderer->viewport(pImpl->vport); //FIXME: The value must be associated with an individual canvas instance. ImageLoader::cs = static_cast(cs); //Paints must be updated again with this new target. - Canvas::pImpl->status = Status::Damaged; + pImpl->status = Status::Damaged; return Result::Success; #endif diff --git a/src/renderer/tvgText.cpp b/src/renderer/tvgText.cpp index 20123e2b..9a93140e 100644 --- a/src/renderer/tvgText.cpp +++ b/src/renderer/tvgText.cpp @@ -24,37 +24,21 @@ #include "tvgText.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ - - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - - -Text::Text() : pImpl(new Impl(this)) +Text::Text() { -} - - -Text::~Text() -{ - delete(pImpl); + pImpl = new Impl(this); } Result Text::text(const char* text) noexcept { - return pImpl->text(text); + return TEXT(this)->text(text); } Result Text::font(const char* name, float size, const char* style) noexcept { - return pImpl->font(name, size, style); + return TEXT(this)->font(name, size, style); } @@ -103,13 +87,13 @@ Result Text::unload(const char* filename) noexcept Result Text::fill(uint8_t r, uint8_t g, uint8_t b) noexcept { - return pImpl->shape->fill(r, g, b); + return TEXT(this)->shape->fill(r, g, b); } Result Text::fill(Fill* f) noexcept { - return pImpl->shape->fill(f); + return TEXT(this)->shape->fill(f); } diff --git a/src/renderer/tvgText.h b/src/renderer/tvgText.h index 07827d63..3283a189 100644 --- a/src/renderer/tvgText.h +++ b/src/renderer/tvgText.h @@ -28,17 +28,18 @@ #include "tvgFill.h" #include "tvgLoader.h" -struct Text::Impl +#define TEXT(A) PIMPL(A, Text) + +struct Text::Impl : Paint::Impl { + Shape* shape; //text shape FontLoader* loader = nullptr; - Text* paint; - Shape* shape; char* utf8 = nullptr; float fontSize; bool italic = false; bool changed = false; - Impl(Text* p) : paint(p), shape(Shape::gen()) + Impl(Text* p) : Paint::Impl(p), shape(Shape::gen()) { } @@ -84,14 +85,14 @@ struct Text::Impl RenderRegion bounds(RenderMethod* renderer) { - return P(shape)->bounds(renderer); + return SHAPE(shape)->bounds(renderer); } bool render(RenderMethod* renderer) { if (!loader) return true; - renderer->blend(PP(paint)->blendMethod); - return PP(shape)->render(renderer); + renderer->blend(blendMethod); + return PAINT(shape)->render(renderer); } bool load() @@ -112,30 +113,31 @@ struct Text::Impl if (!load()) return nullptr; //transform the gradient coordinates based on the final scaled font. - auto fill = P(shape)->rs.fill; - if (fill && P(shape)->rFlag & RenderUpdateFlag::Gradient) { + auto fill = SHAPE(shape)->rs.fill; + if (fill && SHAPE(shape)->renderFlag & RenderUpdateFlag::Gradient) { auto scale = 1.0f / loader->scale; if (fill->type() == Type::LinearGradient) { - P(static_cast(fill))->x1 *= scale; - P(static_cast(fill))->y1 *= scale; - P(static_cast(fill))->x2 *= scale; - P(static_cast(fill))->y2 *= scale; + LINEAR(fill)->x1 *= scale; + LINEAR(fill)->y1 *= scale; + LINEAR(fill)->x2 *= scale; + LINEAR(fill)->y2 *= scale; } else { - P(static_cast(fill))->cx *= scale; - P(static_cast(fill))->cy *= scale; - P(static_cast(fill))->r *= scale; - P(static_cast(fill))->fx *= scale; - P(static_cast(fill))->fy *= scale; - P(static_cast(fill))->fr *= scale; + RADIAL(fill)->cx *= scale; + RADIAL(fill)->cy *= scale; + RADIAL(fill)->r *= scale; + RADIAL(fill)->fx *= scale; + RADIAL(fill)->fy *= scale; + RADIAL(fill)->fr *= scale; } } - return PP(shape)->update(renderer, transform, clips, opacity, pFlag, false); + + return PAINT(shape)->update(renderer, transform, clips, opacity, pFlag, false); } bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking) { if (!load()) return false; - PP(shape)->bounds(x, y, w, h, true, true, false); + PAINT(shape)->bounds(x, y, w, h, true, true, false); return true; } @@ -146,8 +148,8 @@ struct Text::Impl load(); auto text = Text::gen(); - auto dup = text->pImpl; - P(shape)->duplicate(dup->shape); + auto dup = TEXT(text); + SHAPE(shape)->duplicate(dup->shape); if (loader) { dup->loader = loader; diff --git a/src/renderer/tvgWgCanvas.cpp b/src/renderer/tvgWgCanvas.cpp index d9f8e69a..9877b86a 100644 --- a/src/renderer/tvgWgCanvas.cpp +++ b/src/renderer/tvgWgCanvas.cpp @@ -26,32 +26,20 @@ #include "tvgWgRenderer.h" #endif -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ -struct WgCanvas::Impl +WgCanvas::WgCanvas() { -}; - - -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - #ifdef THORVG_WG_RASTER_SUPPORT -WgCanvas::WgCanvas() : Canvas(WgRenderer::gen()), pImpl(nullptr) -#else -WgCanvas::WgCanvas() : Canvas(nullptr), pImpl(nullptr) + pImpl->renderer = WgRenderer::gen(); + pImpl->renderer->ref(); #endif -{ } WgCanvas::~WgCanvas() { #ifdef THORVG_WG_RASTER_SUPPORT - auto renderer = static_cast(Canvas::pImpl->renderer); + auto renderer = static_cast(pImpl->renderer); renderer->target(nullptr, nullptr, nullptr, 0, 0); #endif } @@ -62,20 +50,20 @@ Result WgCanvas::target(void* device, void* instance, void* target, uint32_t w, #ifdef THORVG_WG_RASTER_SUPPORT if (cs != ColorSpace::ABGR8888S) return Result::NonSupport; - if (Canvas::pImpl->status != Status::Damaged && Canvas::pImpl->status != Status::Synced) { + if (pImpl->status != Status::Damaged && pImpl->status != Status::Synced) { return Result::InsufficientCondition; } //We know renderer type, avoid dynamic_cast for performance. - auto renderer = static_cast(Canvas::pImpl->renderer); + auto renderer = static_cast(pImpl->renderer); if (!renderer) return Result::MemoryCorruption; if (!renderer->target((WGPUDevice)device, (WGPUInstance)instance, target, w, h, type)) return Result::Unknown; - Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; - renderer->viewport(Canvas::pImpl->vport); + pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; + renderer->viewport(pImpl->vport); //Paints must be updated again with this new target. - Canvas::pImpl->status = Status::Damaged; + pImpl->status = Status::Damaged; return Result::Success; #endif diff --git a/src/renderer/wg_engine/tvgWgBindGroups.h b/src/renderer/wg_engine/tvgWgBindGroups.h index 63ece6c6..62783244 100755 --- a/src/renderer/wg_engine/tvgWgBindGroups.h +++ b/src/renderer/wg_engine/tvgWgBindGroups.h @@ -39,7 +39,7 @@ public: WGPUBindGroupLayout layoutBuffer1Un{}; WGPUBindGroupLayout layoutBuffer2Un{}; WGPUBindGroupLayout layoutBuffer3Un{}; -public: + WGPUBindGroup createBindGroupTexSampled(WGPUSampler sampler, WGPUTextureView texView); WGPUBindGroup createBindGroupTexSampledBuff1Un(WGPUSampler sampler, WGPUTextureView texView, WGPUBuffer buff); WGPUBindGroup createBindGroupTexSampledBuff2Un(WGPUSampler sampler, WGPUTextureView texView, WGPUBuffer buff0, WGPUBuffer buff1); @@ -52,7 +52,7 @@ public: WGPUBindGroup createBindGroupBuffer3Un(WGPUBuffer buff0, WGPUBuffer buff1, WGPUBuffer buff2); void releaseBindGroup(WGPUBindGroup& bindGroup); void releaseBindGroupLayout(WGPUBindGroupLayout& bindGroupLayout); -public: + void initialize(WGPUDevice device); void release(); }; diff --git a/src/renderer/wg_engine/tvgWgCompositor.h b/src/renderer/wg_engine/tvgWgCompositor.h index 18c8af7d..22505b85 100755 --- a/src/renderer/wg_engine/tvgWgCompositor.h +++ b/src/renderer/wg_engine/tvgWgCompositor.h @@ -62,6 +62,29 @@ private: // viewport utilities RenderRegion shrinkRenderRegion(RenderRegion& rect); + + // shapes + void drawShape(WgContext& context, WgRenderDataShape* renderData); + void blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod); + void clipShape(WgContext& context, WgRenderDataShape* renderData); + + // strokes + void drawStrokes(WgContext& context, WgRenderDataShape* renderData); + void blendStrokes(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod); + void clipStrokes(WgContext& context, WgRenderDataShape* renderData); + + // images + void drawImage(WgContext& context, WgRenderDataPicture* renderData); + void blendImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod); + void clipImage(WgContext& context, WgRenderDataPicture* renderData); + + // scenes + void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose); + void blendScene(WgContext& context, WgRenderStorage* src, WgCompose* compose); + + void renderClipPath(WgContext& context, WgRenderDataPaint* paint); + void clearClipPath(WgContext& context, WgRenderDataPaint* paint); + public: void initialize(WgContext& context, uint32_t width, uint32_t height); void initPools(WgContext& context); @@ -81,28 +104,6 @@ public: // blit render storage to texture view (f.e. screen buffer) void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView); -private: - // shapes - void drawShape(WgContext& context, WgRenderDataShape* renderData); - void blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod); - void clipShape(WgContext& context, WgRenderDataShape* renderData); - - // strokes - void drawStrokes(WgContext& context, WgRenderDataShape* renderData); - void blendStrokes(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod); - void clipStrokes(WgContext& context, WgRenderDataShape* renderData); - - // images - void drawImage(WgContext& context, WgRenderDataPicture* renderData); - void blendImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod); - void clipImage(WgContext& context, WgRenderDataPicture* renderData); - - // scenes - void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose); - void blendScene(WgContext& context, WgRenderStorage* src, WgCompose* compose); -private: - void renderClipPath(WgContext& context, WgRenderDataPaint* paint); - void clearClipPath(WgContext& context, WgRenderDataPaint* paint); }; #endif // _TVG_WG_COMPOSITOR_H_ diff --git a/src/renderer/wg_engine/tvgWgPipelines.h b/src/renderer/wg_engine/tvgWgPipelines.h index 320caee8..c2de880f 100755 --- a/src/renderer/wg_engine/tvgWgPipelines.h +++ b/src/renderer/wg_engine/tvgWgPipelines.h @@ -46,7 +46,7 @@ private: WGPUShaderModule shader_scene_compose{}; // shader blit WGPUShaderModule shader_blit{}; -private: + // layouts helpers WGPUPipelineLayout layout_stencil{}; WGPUPipelineLayout layout_depth{}; @@ -93,7 +93,6 @@ public: WGPURenderPipeline blit{}; private: void releaseGraphicHandles(WgContext& context); -private: WGPUShaderModule createShaderModule(WGPUDevice device, const char* label, const char* code); WGPUPipelineLayout createPipelineLayout(WGPUDevice device, const WGPUBindGroupLayout* bindGroupLayouts, const uint32_t bindGroupLayoutsCount); WGPURenderPipeline createRenderPipeline(