mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
gl_engine: make stencil task support other advance logical
* Support rendering Gradient in path Stroke mode * Fix GlStencilCoverTask not support even-odd fill rule * Make GlStencilCoverTask can discard overlapped area during stroke rendering
This commit is contained in:
parent
54acc7c955
commit
23386625fc
6 changed files with 66 additions and 29 deletions
|
@ -50,6 +50,13 @@
|
|||
} while(0)
|
||||
|
||||
|
||||
enum class GlStencilMode {
|
||||
None,
|
||||
FillWinding,
|
||||
FillEvenOdd,
|
||||
Stroke,
|
||||
};
|
||||
|
||||
class GlGeometry;
|
||||
|
||||
struct GlShape
|
||||
|
|
|
@ -40,7 +40,7 @@ bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag)
|
|||
|
||||
bwTess.tessellate(&rshape);
|
||||
|
||||
mStencilFill = true;
|
||||
mFillRule = rshape.rule;
|
||||
}
|
||||
|
||||
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||
|
@ -154,7 +154,7 @@ bool GlGeometry::draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdate
|
|||
Array<float>* vertexBuffer = nullptr;
|
||||
Array<uint32_t>* indexBuffer = nullptr;
|
||||
|
||||
if (flag & RenderUpdateFlag::Stroke) {
|
||||
if ((flag & RenderUpdateFlag::Stroke) || (flag & RenderUpdateFlag::GradientStroke)) {
|
||||
vertexBuffer = &strokeVertex;
|
||||
indexBuffer = &strokeIndex;
|
||||
} else {
|
||||
|
@ -208,11 +208,14 @@ float* GlGeometry::getTransforMatrix()
|
|||
return mTransform;
|
||||
}
|
||||
|
||||
bool GlGeometry::needStencilCover(RenderUpdateFlag flag)
|
||||
GlStencilMode GlGeometry::getStencilMode(RenderUpdateFlag flag)
|
||||
{
|
||||
if (flag & RenderUpdateFlag::Stroke) return false;
|
||||
if (flag & RenderUpdateFlag::GradientStroke) return false;
|
||||
if (flag & RenderUpdateFlag::Image) return false;
|
||||
if (flag & RenderUpdateFlag::Stroke) return GlStencilMode::Stroke;
|
||||
if (flag & RenderUpdateFlag::GradientStroke) return GlStencilMode::Stroke;
|
||||
if (flag & RenderUpdateFlag::Image) return GlStencilMode::None;
|
||||
|
||||
return mStencilFill;
|
||||
if (mFillRule == FillRule::Winding) return GlStencilMode::FillWinding;
|
||||
if (mFillRule == FillRule::EvenOdd) return GlStencilMode::FillEvenOdd;
|
||||
|
||||
return GlStencilMode::None;
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ public:
|
|||
void updateTransform(const RenderTransform* transform, float w, float h);
|
||||
void setViewport(const RenderRegion& viewport);
|
||||
float* getTransforMatrix();
|
||||
bool needStencilCover(RenderUpdateFlag flag);
|
||||
GlStencilMode getStencilMode(RenderUpdateFlag flag);
|
||||
|
||||
private:
|
||||
RenderRegion viewport = {};
|
||||
|
@ -205,7 +205,7 @@ private:
|
|||
Array<uint32_t> strokeIndex = {};
|
||||
float mTransform[16];
|
||||
|
||||
bool mStencilFill = false;
|
||||
FillRule mFillRule = FillRule::Winding;
|
||||
};
|
||||
|
||||
#endif /* _TVG_GL_GEOMETRY_H_ */
|
||||
|
|
|
@ -99,8 +99,8 @@ void GlRenderTask::setViewport(const RenderRegion &viewport)
|
|||
mViewport = viewport;
|
||||
}
|
||||
|
||||
GlStencilCoverTask::GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover)
|
||||
:GlRenderTask(nullptr), mStencilTask(stencil), mCoverTask(cover) {}
|
||||
GlStencilCoverTask::GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover, GlStencilMode mode)
|
||||
:GlRenderTask(nullptr), mStencilTask(stencil), mCoverTask(cover), mStencilMode(mode) {}
|
||||
|
||||
GlStencilCoverTask::~GlStencilCoverTask()
|
||||
{
|
||||
|
@ -112,23 +112,43 @@ void GlStencilCoverTask::run()
|
|||
{
|
||||
GL_CHECK(glEnable(GL_STENCIL_TEST));
|
||||
|
||||
GL_CHECK(glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0x1, 0xFF));
|
||||
GL_CHECK(glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP));
|
||||
|
||||
GL_CHECK(glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0x1, 0xFF));
|
||||
GL_CHECK(glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP));
|
||||
if (mStencilMode == GlStencilMode::Stroke) {
|
||||
GL_CHECK(glStencilFunc(GL_NOTEQUAL, 0x1, 0xFF));
|
||||
GL_CHECK(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
||||
} else {
|
||||
GL_CHECK(glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0x1, 0xFF));
|
||||
GL_CHECK(glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP));
|
||||
|
||||
GL_CHECK(glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0x1, 0xFF));
|
||||
GL_CHECK(glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP));
|
||||
}
|
||||
GL_CHECK(glColorMask(0, 0, 0, 0));
|
||||
|
||||
mStencilTask->run();
|
||||
|
||||
GL_CHECK(glStencilFunc(GL_NOTEQUAL, 0x0, 0xFF));
|
||||
GL_CHECK(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
||||
if (mStencilMode == GlStencilMode::FillEvenOdd) {
|
||||
GL_CHECK(glStencilFunc(GL_EQUAL, 0x01, 0x01));
|
||||
GL_CHECK(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
||||
} else {
|
||||
GL_CHECK(glStencilFunc(GL_NOTEQUAL, 0x0, 0xFF));
|
||||
GL_CHECK(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
||||
}
|
||||
|
||||
GL_CHECK(glColorMask(1, 1, 1, 1));
|
||||
|
||||
mCoverTask->run();
|
||||
|
||||
if (mStencilMode == GlStencilMode::FillEvenOdd) {
|
||||
GL_CHECK(glStencilFunc(GL_NOTEQUAL, 0x0, 0xFF));
|
||||
GL_CHECK(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
||||
|
||||
GL_CHECK(glColorMask(0, 0, 0, 0));
|
||||
|
||||
mStencilTask->run();
|
||||
|
||||
GL_CHECK(glColorMask(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
GL_CHECK(glDisable(GL_STENCIL_TEST));
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ private:
|
|||
class GlStencilCoverTask : public GlRenderTask
|
||||
{
|
||||
public:
|
||||
GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover);
|
||||
GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover, GlStencilMode mode);
|
||||
~GlStencilCoverTask() override;
|
||||
|
||||
void run() override;
|
||||
|
@ -108,6 +108,7 @@ public:
|
|||
private:
|
||||
GlRenderTask* mStencilTask;
|
||||
GlRenderTask* mCoverTask;
|
||||
GlStencilMode mStencilMode;
|
||||
};
|
||||
|
||||
class GlRenderTarget;
|
||||
|
|
|
@ -266,12 +266,17 @@ bool GlRenderer::renderShape(RenderData data)
|
|||
}
|
||||
}
|
||||
|
||||
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
|
||||
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::GradientStroke | RenderUpdateFlag::Transform))
|
||||
{
|
||||
sdata->rshape->strokeFill(&r, &g, &b, &a);
|
||||
if (a > 0)
|
||||
{
|
||||
drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Stroke);
|
||||
auto gradient = sdata->rshape->strokeFill();
|
||||
if (gradient) {
|
||||
drawPrimitive(*sdata, gradient, RenderUpdateFlag::GradientStroke);
|
||||
} else {
|
||||
sdata->rshape->strokeFill(&r, &g, &b, &a);
|
||||
if (a > 0)
|
||||
{
|
||||
drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Stroke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,7 +496,8 @@ void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b,
|
|||
|
||||
GlRenderTask* stencilTask = nullptr;
|
||||
|
||||
if (sdata.geometry->needStencilCover(flag)) stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task);
|
||||
GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag);
|
||||
if (stencilMode != GlStencilMode::None) stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task);
|
||||
|
||||
a = MULTIPLY(a, sdata.opacity);
|
||||
|
||||
|
@ -536,7 +542,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b,
|
|||
}
|
||||
|
||||
if (stencilTask) {
|
||||
currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task));
|
||||
currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode));
|
||||
} else {
|
||||
currentPass()->addRenderTask(task);
|
||||
}
|
||||
|
@ -563,8 +569,8 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
|
|||
if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) return;
|
||||
|
||||
GlRenderTask* stencilTask = nullptr;
|
||||
|
||||
if (sdata.geometry->needStencilCover(flag)) stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task);
|
||||
GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag);
|
||||
if (stencilMode != GlStencilMode::None) stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task);
|
||||
|
||||
// matrix buffer
|
||||
{
|
||||
|
@ -668,7 +674,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
|
|||
}
|
||||
|
||||
if (stencilTask) {
|
||||
currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task));
|
||||
currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode));
|
||||
} else {
|
||||
currentPass()->addRenderTask(task);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue