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)
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
enum class GlStencilMode {
|
||||||
|
None,
|
||||||
|
FillWinding,
|
||||||
|
FillEvenOdd,
|
||||||
|
Stroke,
|
||||||
|
};
|
||||||
|
|
||||||
class GlGeometry;
|
class GlGeometry;
|
||||||
|
|
||||||
struct GlShape
|
struct GlShape
|
||||||
|
|
|
@ -40,7 +40,7 @@ bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag)
|
||||||
|
|
||||||
bwTess.tessellate(&rshape);
|
bwTess.tessellate(&rshape);
|
||||||
|
|
||||||
mStencilFill = true;
|
mFillRule = rshape.rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||||
|
@ -154,7 +154,7 @@ bool GlGeometry::draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdate
|
||||||
Array<float>* vertexBuffer = nullptr;
|
Array<float>* vertexBuffer = nullptr;
|
||||||
Array<uint32_t>* indexBuffer = nullptr;
|
Array<uint32_t>* indexBuffer = nullptr;
|
||||||
|
|
||||||
if (flag & RenderUpdateFlag::Stroke) {
|
if ((flag & RenderUpdateFlag::Stroke) || (flag & RenderUpdateFlag::GradientStroke)) {
|
||||||
vertexBuffer = &strokeVertex;
|
vertexBuffer = &strokeVertex;
|
||||||
indexBuffer = &strokeIndex;
|
indexBuffer = &strokeIndex;
|
||||||
} else {
|
} else {
|
||||||
|
@ -208,11 +208,14 @@ float* GlGeometry::getTransforMatrix()
|
||||||
return mTransform;
|
return mTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GlGeometry::needStencilCover(RenderUpdateFlag flag)
|
GlStencilMode GlGeometry::getStencilMode(RenderUpdateFlag flag)
|
||||||
{
|
{
|
||||||
if (flag & RenderUpdateFlag::Stroke) return false;
|
if (flag & RenderUpdateFlag::Stroke) return GlStencilMode::Stroke;
|
||||||
if (flag & RenderUpdateFlag::GradientStroke) return false;
|
if (flag & RenderUpdateFlag::GradientStroke) return GlStencilMode::Stroke;
|
||||||
if (flag & RenderUpdateFlag::Image) return false;
|
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 updateTransform(const RenderTransform* transform, float w, float h);
|
||||||
void setViewport(const RenderRegion& viewport);
|
void setViewport(const RenderRegion& viewport);
|
||||||
float* getTransforMatrix();
|
float* getTransforMatrix();
|
||||||
bool needStencilCover(RenderUpdateFlag flag);
|
GlStencilMode getStencilMode(RenderUpdateFlag flag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RenderRegion viewport = {};
|
RenderRegion viewport = {};
|
||||||
|
@ -205,7 +205,7 @@ private:
|
||||||
Array<uint32_t> strokeIndex = {};
|
Array<uint32_t> strokeIndex = {};
|
||||||
float mTransform[16];
|
float mTransform[16];
|
||||||
|
|
||||||
bool mStencilFill = false;
|
FillRule mFillRule = FillRule::Winding;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _TVG_GL_GEOMETRY_H_ */
|
#endif /* _TVG_GL_GEOMETRY_H_ */
|
||||||
|
|
|
@ -99,8 +99,8 @@ void GlRenderTask::setViewport(const RenderRegion &viewport)
|
||||||
mViewport = viewport;
|
mViewport = viewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
GlStencilCoverTask::GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover)
|
GlStencilCoverTask::GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover, GlStencilMode mode)
|
||||||
:GlRenderTask(nullptr), mStencilTask(stencil), mCoverTask(cover) {}
|
:GlRenderTask(nullptr), mStencilTask(stencil), mCoverTask(cover), mStencilMode(mode) {}
|
||||||
|
|
||||||
GlStencilCoverTask::~GlStencilCoverTask()
|
GlStencilCoverTask::~GlStencilCoverTask()
|
||||||
{
|
{
|
||||||
|
@ -112,23 +112,43 @@ void GlStencilCoverTask::run()
|
||||||
{
|
{
|
||||||
GL_CHECK(glEnable(GL_STENCIL_TEST));
|
GL_CHECK(glEnable(GL_STENCIL_TEST));
|
||||||
|
|
||||||
GL_CHECK(glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0x1, 0xFF));
|
if (mStencilMode == GlStencilMode::Stroke) {
|
||||||
GL_CHECK(glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP));
|
GL_CHECK(glStencilFunc(GL_NOTEQUAL, 0x1, 0xFF));
|
||||||
|
GL_CHECK(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
||||||
GL_CHECK(glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0x1, 0xFF));
|
} else {
|
||||||
GL_CHECK(glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP));
|
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));
|
GL_CHECK(glColorMask(0, 0, 0, 0));
|
||||||
|
|
||||||
mStencilTask->run();
|
mStencilTask->run();
|
||||||
|
|
||||||
GL_CHECK(glStencilFunc(GL_NOTEQUAL, 0x0, 0xFF));
|
if (mStencilMode == GlStencilMode::FillEvenOdd) {
|
||||||
GL_CHECK(glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
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));
|
GL_CHECK(glColorMask(1, 1, 1, 1));
|
||||||
|
|
||||||
mCoverTask->run();
|
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));
|
GL_CHECK(glDisable(GL_STENCIL_TEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ private:
|
||||||
class GlStencilCoverTask : public GlRenderTask
|
class GlStencilCoverTask : public GlRenderTask
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover);
|
GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover, GlStencilMode mode);
|
||||||
~GlStencilCoverTask() override;
|
~GlStencilCoverTask() override;
|
||||||
|
|
||||||
void run() override;
|
void run() override;
|
||||||
|
@ -108,6 +108,7 @@ public:
|
||||||
private:
|
private:
|
||||||
GlRenderTask* mStencilTask;
|
GlRenderTask* mStencilTask;
|
||||||
GlRenderTask* mCoverTask;
|
GlRenderTask* mCoverTask;
|
||||||
|
GlStencilMode mStencilMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GlRenderTarget;
|
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);
|
auto gradient = sdata->rshape->strokeFill();
|
||||||
if (a > 0)
|
if (gradient) {
|
||||||
{
|
drawPrimitive(*sdata, gradient, RenderUpdateFlag::GradientStroke);
|
||||||
drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Stroke);
|
} 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;
|
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);
|
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) {
|
if (stencilTask) {
|
||||||
currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task));
|
currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode));
|
||||||
} else {
|
} else {
|
||||||
currentPass()->addRenderTask(task);
|
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;
|
if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) return;
|
||||||
|
|
||||||
GlRenderTask* stencilTask = nullptr;
|
GlRenderTask* stencilTask = nullptr;
|
||||||
|
GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag);
|
||||||
if (sdata.geometry->needStencilCover(flag)) stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task);
|
if (stencilMode != GlStencilMode::None) stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task);
|
||||||
|
|
||||||
// matrix buffer
|
// matrix buffer
|
||||||
{
|
{
|
||||||
|
@ -668,7 +674,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stencilTask) {
|
if (stencilTask) {
|
||||||
currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task));
|
currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode));
|
||||||
} else {
|
} else {
|
||||||
currentPass()->addRenderTask(task);
|
currentPass()->addRenderTask(task);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue