diff --git a/src/renderer/gl_engine/tvgGlCommon.h b/src/renderer/gl_engine/tvgGlCommon.h index 9ed9325d..52bb0325 100644 --- a/src/renderer/gl_engine/tvgGlCommon.h +++ b/src/renderer/gl_engine/tvgGlCommon.h @@ -93,5 +93,11 @@ struct GlRadialGradientBlock alignas(16) float stopColors[4 * MAX_GRADIENT_STOPS] = {}; }; +struct GlCompositor : public Compositor +{ + RenderRegion bbox = {}; + + GlCompositor(const RenderRegion& box) : bbox(box) {} +}; #endif /* _TVG_GL_COMMON_H_ */ diff --git a/src/renderer/gl_engine/tvgGlGeometry.cpp b/src/renderer/gl_engine/tvgGlGeometry.cpp index d5168bb7..5a0a35a5 100644 --- a/src/renderer/gl_engine/tvgGlGeometry.cpp +++ b/src/renderer/gl_engine/tvgGlGeometry.cpp @@ -38,17 +38,21 @@ bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag) BWTessellator bwTess{&fillVertex, &fillIndex}; - bwTess.tessellate(&rshape); + bwTess.tessellate(&rshape, mMatrix); mFillRule = rshape.rule; + + mBounds = bwTess.bounds(); } if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { strokeVertex.clear(); strokeIndex.clear(); - Stroker stroke{&strokeVertex, &strokeIndex}; + Stroker stroke{&strokeVertex, &strokeIndex, mMatrix}; stroke.stroke(&rshape); + + mBounds = stroke.bounds(); } return true; @@ -90,6 +94,32 @@ bool GlGeometry::tesselate(const Surface* image, const RenderMesh* mesh, RenderU index += 3; } + float left = mesh->triangles[0].vertex[0].pt.x; + float top = mesh->triangles[0].vertex[0].pt.y; + float right = mesh->triangles[0].vertex[0].pt.x; + float bottom = mesh->triangles[0].vertex[0].pt.y; + + for (uint32_t i = 0; i < mesh->triangleCnt; i++) { + left = min(left, mesh->triangles[i].vertex[0].pt.x); + left = min(left, mesh->triangles[i].vertex[1].pt.x); + left = min(left, mesh->triangles[i].vertex[2].pt.x); + top = min(top, mesh->triangles[i].vertex[0].pt.y); + top = min(top, mesh->triangles[i].vertex[1].pt.y); + top = min(top, mesh->triangles[i].vertex[2].pt.y); + + right = max(right, mesh->triangles[i].vertex[0].pt.x); + right = max(right, mesh->triangles[i].vertex[1].pt.x); + right = max(right, mesh->triangles[i].vertex[2].pt.x); + bottom = max(bottom, mesh->triangles[i].vertex[0].pt.y); + bottom = max(bottom, mesh->triangles[i].vertex[1].pt.y); + bottom = max(bottom, mesh->triangles[i].vertex[2].pt.y); + } + + mBounds.x = static_cast(left); + mBounds.y = static_cast(top); + mBounds.w = static_cast(right - left); + mBounds.h = static_cast(bottom - top); + } else { fillVertex.reserve(5 * 4); fillIndex.reserve(6); @@ -131,6 +161,11 @@ bool GlGeometry::tesselate(const Surface* image, const RenderMesh* mesh, RenderU fillIndex.push(2); fillIndex.push(1); fillIndex.push(3); + + mBounds.x = 0; + mBounds.y = 0; + mBounds.w = image->w; + mBounds.h = image->h; } } @@ -186,12 +221,15 @@ void GlGeometry::updateTransform(const RenderTransform* transform, float w, floa float modelMatrix[16]; if (transform) { GET_MATRIX44(transform->m, modelMatrix); + mMatrix = transform->m; } else { memset(modelMatrix, 0, 16 * sizeof(float)); modelMatrix[0] = 1.f; modelMatrix[5] = 1.f; modelMatrix[10] = 1.f; modelMatrix[15] = 1.f; + + mMatrix = Matrix{1, 0, 0, 0, 1, 0, 0, 0, 1}; } MVP_MATRIX(); @@ -219,3 +257,37 @@ GlStencilMode GlGeometry::getStencilMode(RenderUpdateFlag flag) return GlStencilMode::None; } + +RenderRegion GlGeometry::getBounds() const +{ + if (mathIdentity(&mMatrix)) { + return mBounds; + } else { + Point lt{static_cast(mBounds.x), static_cast(mBounds.y)}; + Point lb{static_cast(mBounds.x), static_cast(mBounds.y + mBounds.h)}; + Point rt{static_cast(mBounds.x + mBounds.w), static_cast(mBounds.y)}; + Point rb{static_cast(mBounds.x + mBounds.w), static_cast(mBounds.y + mBounds.h)}; + + mathMultiply(<, &mMatrix); + mathMultiply(&lb, &mMatrix); + mathMultiply(&rt, &mMatrix); + mathMultiply(&rb, &mMatrix); + + float left = min(min(lt.x, lb.x), min(rt.x, rb.x)); + float top = min(min(lt.y, lb.y), min(rt.y, rb.y)); + float right = max(max(lt.x, lb.x), max(rt.x, rb.x)); + float bottom = max(max(lt.y, lb.y), max(rt.y, rb.y)); + + auto bounds = RenderRegion { + static_cast(left), + static_cast(top), + static_cast(right - left), + static_cast(bottom - top), + }; + if (bounds.x < 0 || bounds.y < 0 || bounds.w < 0 || bounds.h < 0) { + return mBounds; + } else { + return bounds; + } + } +} diff --git a/src/renderer/gl_engine/tvgGlGeometry.h b/src/renderer/gl_engine/tvgGlGeometry.h index 62c646db..acdf5c3e 100644 --- a/src/renderer/gl_engine/tvgGlGeometry.h +++ b/src/renderer/gl_engine/tvgGlGeometry.h @@ -196,6 +196,7 @@ public: void setViewport(const RenderRegion& viewport); float* getTransforMatrix(); GlStencilMode getStencilMode(RenderUpdateFlag flag); + RenderRegion getBounds() const; private: RenderRegion viewport = {}; @@ -204,8 +205,10 @@ private: Array fillIndex = {}; Array strokeIndex = {}; float mTransform[16]; + Matrix mMatrix = {}; FillRule mFillRule = FillRule::Winding; + RenderRegion mBounds = {}; }; #endif /* _TVG_GL_GEOMETRY_H_ */ diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index f6539223..9b65de13 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -133,9 +133,10 @@ bool GlRenderer::sync() } -RenderRegion GlRenderer::region(TVG_UNUSED RenderData data) +RenderRegion GlRenderer::region(RenderData data) { - return {0, 0, static_cast(surface.w), static_cast(surface.h)}; + auto shape = reinterpret_cast(data); + return shape->geometry->getBounds(); } @@ -158,9 +159,9 @@ bool GlRenderer::postRender() } -Compositor* GlRenderer::target(TVG_UNUSED const RenderRegion& region, TVG_UNUSED ColorSpace cs) +Compositor* GlRenderer::target(const RenderRegion& region, TVG_UNUSED ColorSpace cs) { - mComposeStack.emplace_back(make_unique()); + mComposeStack.emplace_back(make_unique(region)); return mComposeStack.back().get(); } @@ -209,6 +210,9 @@ ColorSpace GlRenderer::colorSpace() bool GlRenderer::blend(TVG_UNUSED BlendMethod method) { + if (method != BlendMethod::Normal) { + return true; + } //TODO: return false; } @@ -273,6 +277,8 @@ bool GlRenderer::renderShape(RenderData data) auto sdata = static_cast(data); if (!sdata) return false; + if (sdata->updateFlag == RenderUpdateFlag::None) return false; + if (!sdata->clips.empty()) drawClip(sdata->clips); uint8_t r = 0, g = 0, b = 0, a = 0; @@ -351,7 +357,7 @@ RenderData GlRenderer::prepare(Surface* image, const RenderMesh* mesh, RenderDat sdata->viewWd = static_cast(surface.w); sdata->viewHt = static_cast(surface.h); - sdata->updateFlag = flags; + sdata->updateFlag = RenderUpdateFlag::Image; if (sdata->texId == 0) { sdata->texId = _genTexture(image); @@ -398,9 +404,7 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const sdata->viewWd = static_cast(surface.w); sdata->viewHt = static_cast(surface.h); - sdata->updateFlag = flags; - - if (sdata->updateFlag == RenderUpdateFlag::None) return sdata; + sdata->updateFlag = RenderUpdateFlag::None; sdata->geometry = make_unique(); sdata->opacity = opacity; @@ -417,6 +421,17 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const return sdata; } + if (clipper) { + sdata->updateFlag = RenderUpdateFlag::Path; + } else { + if (alphaF) sdata->updateFlag = static_cast(RenderUpdateFlag::Color | sdata->updateFlag); + if (rshape.fill) sdata->updateFlag = static_cast(RenderUpdateFlag::Gradient | sdata->updateFlag); + if (alphaS) sdata->updateFlag = static_cast(RenderUpdateFlag::Stroke | sdata->updateFlag); + if (rshape.strokeFill()) sdata->updateFlag = static_cast(RenderUpdateFlag::GradientStroke | sdata->updateFlag); + } + + if (sdata->updateFlag == RenderUpdateFlag::None) return sdata; + sdata->geometry->updateTransform(transform, sdata->viewWd, sdata->viewHt); sdata->geometry->setViewport(RenderRegion{ mViewport.x, @@ -835,7 +850,7 @@ GlRenderPass* GlRenderer::currentPass() void GlRenderer::prepareBlitTask(GlBlitTask* task) { - prepareCmpTask(task); + prepareCmpTask(task, mViewport); { uint32_t loc = task->getProgram()->getUniformLocation("uSrcTexture"); @@ -843,7 +858,7 @@ void GlRenderer::prepareBlitTask(GlBlitTask* task) } } -void GlRenderer::prepareCmpTask(GlRenderTask* task) +void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp) { // we use 1:1 blit mapping since compositor fbo is same size as root fbo Array vertices(4 * 4); @@ -891,15 +906,16 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task) task->setDrawRange(indexOffset, indices.count); task->setViewport(RenderRegion{ - mViewport.x, - static_cast((surface.h - mViewport.y - mViewport.h)), - mViewport.w, - mViewport.h, + vp.x, + static_cast((surface.h - vp.y - vp.h)), + vp.w, + vp.h, }); } void GlRenderer::endRenderPass(Compositor* cmp) { + auto gl_cmp = static_cast(cmp); if (cmp->method != CompositeMethod::None) { auto self_pass = std::move(mRenderPassStack.back()); mRenderPassStack.pop_back(); @@ -949,7 +965,7 @@ void GlRenderer::endRenderPass(Compositor* cmp) auto compose_task = self_pass.endRenderPass(program, currentPass()->getFboId()); - prepareCmpTask(compose_task); + prepareCmpTask(compose_task, gl_cmp->bbox); { uint32_t loc = program->getUniformLocation("uSrcTexture"); @@ -971,7 +987,7 @@ void GlRenderer::endRenderPass(Compositor* cmp) auto task = renderPass.endRenderPass( mPrograms[RT_Image].get(), currentPass()->getFboId()); - prepareCmpTask(task); + prepareCmpTask(task, gl_cmp->bbox); // matrix buffer { diff --git a/src/renderer/gl_engine/tvgGlRenderer.h b/src/renderer/gl_engine/tvgGlRenderer.h index 5a63a475..e2983e55 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.h +++ b/src/renderer/gl_engine/tvgGlRenderer.h @@ -93,7 +93,7 @@ private: GlRenderPass* currentPass(); void prepareBlitTask(GlBlitTask* task); - void prepareCmpTask(GlRenderTask* task); + void prepareCmpTask(GlRenderTask* task, const RenderRegion& vp); void endRenderPass(Compositor* cmp); GLint mTargetFboId = 0; @@ -105,7 +105,7 @@ private: unique_ptr mRootTarget = {}; Array mComposePool = {}; vector mRenderPassStack = {}; - vector> mComposeStack = {}; + vector> mComposeStack = {}; bool mClearBuffer = true; }; diff --git a/src/renderer/gl_engine/tvgGlTessellator.cpp b/src/renderer/gl_engine/tvgGlTessellator.cpp index e5efe9e2..c1bd92d0 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.cpp +++ b/src/renderer/gl_engine/tvgGlTessellator.cpp @@ -1638,7 +1638,7 @@ void Tessellator::emitTriangle(detail::Vertex *p1, detail::Vertex *p2, detail::V } -Stroker::Stroker(Array *points, Array *indices) : mResGlPoints(points), mResIndices(indices) +Stroker::Stroker(Array *points, Array *indices, const Matrix& matrix) : mResGlPoints(points), mResIndices(indices), mMatrix(matrix) { } @@ -1665,6 +1665,16 @@ void Stroker::stroke(const RenderShape *rshape) } } +RenderRegion Stroker::bounds() const +{ + return RenderRegion { + static_cast(mLeftTop.x), + static_cast(mLeftTop.y), + static_cast(mRightBottom.x - mLeftTop.x), + static_cast(mRightBottom.y - mLeftTop.y), + }; +} + void Stroker::doStroke(const PathCommand *cmds, uint32_t cmd_count, const Point *pts, uint32_t pts_count) { mResGlPoints->reserve(pts_count * 4 + 16); @@ -1773,6 +1783,16 @@ void Stroker::strokeLineTo(const GlPoint &curr) mStrokeState.prevPtDir = dir; mStrokeState.prevPt = curr; } + + if (ia == 0) { + mRightBottom.x = mLeftTop.x = curr.x; + mRightBottom.y = mLeftTop.y = curr.y; + } else { + mLeftTop.x = min(mLeftTop.x, curr.x); + mLeftTop.y = min(mLeftTop.y, curr.y); + mRightBottom.x = max(mRightBottom.x, curr.x); + mRightBottom.y = max(mRightBottom.y , curr.y); + } } void Stroker::strokeCubicTo(const GlPoint &cnt1, const GlPoint &cnt2, const GlPoint &end) @@ -1783,7 +1803,13 @@ void Stroker::strokeCubicTo(const GlPoint &cnt1, const GlPoint &cnt2, const GlPo curve.ctrl2 = Point{cnt2.x, cnt2.y}; curve.end = Point{end.x, end.y}; - auto count = detail::_bezierCurveCount(curve); + Bezier relCurve {curve.start, curve.ctrl1, curve.ctrl2, curve.end}; + mathMultiply(&relCurve.start, &mMatrix); + mathMultiply(&relCurve.ctrl1, &mMatrix); + mathMultiply(&relCurve.ctrl2, &mMatrix); + mathMultiply(&relCurve.end, &mMatrix); + + auto count = detail::_bezierCurveCount(relCurve); float step = 1.f / count; @@ -2110,7 +2136,7 @@ BWTessellator::BWTessellator(Array* points, Array* indices): mR { } -void BWTessellator::tessellate(const RenderShape *rshape) +void BWTessellator::tessellate(const RenderShape *rshape, const Matrix& matrix) { auto cmds = rshape->path.cmds.data; auto cmdCnt = rshape->path.cmds.count; @@ -2148,7 +2174,13 @@ void BWTessellator::tessellate(const RenderShape *rshape) case PathCommand::CubicTo: { Bezier curve{pts[-1], pts[0], pts[1], pts[2]}; - auto stepCount = detail::_bezierCurveCount(curve); + Bezier relCurve {pts[-1], pts[0], pts[1], pts[2]}; + mathMultiply(&relCurve.start, &matrix); + mathMultiply(&relCurve.ctrl1, &matrix); + mathMultiply(&relCurve.ctrl2, &matrix); + mathMultiply(&relCurve.end, &matrix); + + auto stepCount = detail::_bezierCurveCount(relCurve); if (stepCount <= 1) stepCount = 2; @@ -2176,9 +2208,31 @@ void BWTessellator::tessellate(const RenderShape *rshape) } } +RenderRegion BWTessellator::bounds() const +{ + return RenderRegion { + static_cast(mLeftTop.x), + static_cast(mLeftTop.y), + static_cast(mRightBottom.x - mLeftTop.x), + static_cast(mRightBottom.y - mLeftTop.y), + }; +} + uint32_t BWTessellator::pushVertex(float x, float y) { - return detail::_pushVertex(mResPoints, x, y); + auto index = detail::_pushVertex(mResPoints, x, y); + + if (index == 0) { + mRightBottom.x = mLeftTop.x = x; + mRightBottom.y = mLeftTop.y = y; + } else { + mLeftTop.x = min(mLeftTop.x, x); + mLeftTop.y = min(mLeftTop.y, y); + mRightBottom.x = max(mRightBottom.x, x); + mRightBottom.y = max(mRightBottom.y , y); + } + + return index; } void BWTessellator::pushTriangle(uint32_t a, uint32_t b, uint32_t c) diff --git a/src/renderer/gl_engine/tvgGlTessellator.h b/src/renderer/gl_engine/tvgGlTessellator.h index 83bccec4..405b7fa9 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.h +++ b/src/renderer/gl_engine/tvgGlTessellator.h @@ -108,11 +108,13 @@ class Stroker final bool hasMove = false; }; public: - Stroker(Array* points, Array* indices); + Stroker(Array* points, Array* indices, const Matrix& matrix); ~Stroker() = default; void stroke(const RenderShape *rshape); + RenderRegion bounds() const; + private: void doStroke(const PathCommand* cmds, uint32_t cmd_count, const Point* pts, uint32_t pts_count); void doDashStroke(const PathCommand* cmds, uint32_t cmd_count, const Point* pts, uint32_t pts_count, @@ -141,11 +143,14 @@ private: private: Array* mResGlPoints; Array* mResIndices; + Matrix mMatrix; float mStrokeWidth = 1.f; float mMiterLimit = 4.f; StrokeCap mStrokeCap = StrokeCap::Square; StrokeJoin mStrokeJoin = StrokeJoin::Bevel; State mStrokeState = {}; + GlPoint mLeftTop = {}; + GlPoint mRightBottom = {}; }; class DashStroke @@ -183,7 +188,9 @@ public: BWTessellator(Array* points, Array* indices); ~BWTessellator() = default; - void tessellate(const RenderShape *rshape); + void tessellate(const RenderShape *rshape, const Matrix& matrix); + + RenderRegion bounds() const; private: uint32_t pushVertex(float x, float y); @@ -192,6 +199,8 @@ private: private: Array* mResPoints; Array* mResIndices; + GlPoint mLeftTop = {}; + GlPoint mRightBottom = {}; }; } // namespace tvg