mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-26 08:09:14 +00:00
gl_engine: introduce dropshadow effect for opengl renderer
issue: https://github.com/thorvg/thorvg/issues/3054
This commit is contained in:
parent
5c27fefef8
commit
6c3fee84ec
7 changed files with 182 additions and 2 deletions
|
@ -208,6 +208,11 @@ struct GlGaussianBlur {
|
||||||
float extend{};
|
float extend{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GlDropShadow: GlGaussianBlur {
|
||||||
|
float color[4];
|
||||||
|
float offset[2];
|
||||||
|
};
|
||||||
|
|
||||||
struct GlEffectParams {
|
struct GlEffectParams {
|
||||||
// fill: [0..3]: color
|
// fill: [0..3]: color
|
||||||
// tint: [0..2]: black, [4..6]: white, [8]: intensity
|
// tint: [0..2]: black, [4..6]: white, [8]: intensity
|
||||||
|
|
|
@ -435,6 +435,60 @@ void GlGaussianBlurTask::run()
|
||||||
GL_CHECK(glEnable(GL_BLEND));
|
GL_CHECK(glEnable(GL_BLEND));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GlEffectDropShadowTask::run()
|
||||||
|
{
|
||||||
|
const auto vp = getViewport();
|
||||||
|
const auto width = mDstFbo->getWidth();
|
||||||
|
const auto height = mDstFbo->getHeight();
|
||||||
|
|
||||||
|
// get targets handles
|
||||||
|
GLuint dstCopyTexId0 = mDstCopyFbo0->getColorTexture();
|
||||||
|
GLuint dstCopyTexId1 = mDstCopyFbo1->getColorTexture();
|
||||||
|
// get programs properties
|
||||||
|
GlProgram* programHorz = horzTask->getProgram();
|
||||||
|
GlProgram* programVert = vertTask->getProgram();
|
||||||
|
GLint horzSrcTextureLoc = programHorz->getUniformLocation("uSrcTexture");
|
||||||
|
GLint vertSrcTextureLoc = programVert->getUniformLocation("uSrcTexture");
|
||||||
|
|
||||||
|
GLint srcTextureLoc = getProgram()->getUniformLocation("uSrcTexture");
|
||||||
|
GLint blrTextureLoc = getProgram()->getUniformLocation("uBlrTexture");
|
||||||
|
addBindResource({ 0, dstCopyTexId0, srcTextureLoc });
|
||||||
|
addBindResource({ 1, dstCopyTexId1, blrTextureLoc });
|
||||||
|
|
||||||
|
GL_CHECK(glViewport(0, 0, width, height));
|
||||||
|
GL_CHECK(glScissor(0, 0, width, height));
|
||||||
|
|
||||||
|
// we need to make a full copy of dst to intermediate buffers to be sure that they don’t contain prev data.
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId()));
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo0->getResolveFboId()));
|
||||||
|
GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST));
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId()));
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo1->getResolveFboId()));
|
||||||
|
GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST));
|
||||||
|
|
||||||
|
GL_CHECK(glDisable(GL_BLEND));
|
||||||
|
// horizontal blur
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstCopyFbo0->getResolveFboId()));
|
||||||
|
horzTask->setViewport(vp);
|
||||||
|
horzTask->addBindResource({ 0, dstCopyTexId1, horzSrcTextureLoc });
|
||||||
|
horzTask->run();
|
||||||
|
// vertical blur
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstCopyFbo1->getResolveFboId()));
|
||||||
|
vertTask->setViewport(vp);
|
||||||
|
vertTask->addBindResource({ 0, dstCopyTexId0, vertSrcTextureLoc });
|
||||||
|
vertTask->run();
|
||||||
|
// copy original image to intermediate buffer
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId()));
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo0->getResolveFboId()));
|
||||||
|
GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST));
|
||||||
|
// run drop shadow effect
|
||||||
|
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstFbo->getFboId()));
|
||||||
|
GlRenderTask::run();
|
||||||
|
GL_CHECK(glEnable(GL_BLEND));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GlEffectColorTransformTask::run()
|
void GlEffectColorTransformTask::run()
|
||||||
{
|
{
|
||||||
const auto width = mDstFbo->getWidth();
|
const auto width = mDstFbo->getWidth();
|
||||||
|
|
|
@ -237,6 +237,24 @@ private:
|
||||||
GlRenderTarget* mDstCopyFbo1;
|
GlRenderTarget* mDstCopyFbo1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GlEffectDropShadowTask: public GlRenderTask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GlEffectDropShadowTask(GlProgram* program, GlRenderTarget* dstFbo, GlRenderTarget* dstCopyFbo0, GlRenderTarget* dstCopyFbo1):
|
||||||
|
GlRenderTask(program), mDstFbo(dstFbo), mDstCopyFbo0(dstCopyFbo0), mDstCopyFbo1(dstCopyFbo1) {};
|
||||||
|
~GlEffectDropShadowTask(){ delete horzTask; delete vertTask; };
|
||||||
|
|
||||||
|
void run() override;
|
||||||
|
|
||||||
|
GlRenderTask* horzTask;
|
||||||
|
GlRenderTask* vertTask;
|
||||||
|
RenderEffectDropShadow* effect;
|
||||||
|
private:
|
||||||
|
GlRenderTarget* mDstFbo;
|
||||||
|
GlRenderTarget* mDstCopyFbo0;
|
||||||
|
GlRenderTarget* mDstCopyFbo1;
|
||||||
|
};
|
||||||
|
|
||||||
class GlEffectColorTransformTask: public GlRenderTask
|
class GlEffectColorTransformTask: public GlRenderTask
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -144,6 +144,7 @@ void GlRenderer::initShaders()
|
||||||
// effects
|
// effects
|
||||||
mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_VERTICAL));
|
mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_VERTICAL));
|
||||||
mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_HORIZONTAL));
|
mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_HORIZONTAL));
|
||||||
|
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_DROPSHADOW));
|
||||||
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_FILL));
|
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_FILL));
|
||||||
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_TINT));
|
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_TINT));
|
||||||
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_TRITONE));
|
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_TRITONE));
|
||||||
|
@ -964,6 +965,32 @@ void GlRenderer::effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GlRenderer::effectDropShadowUpdate(RenderEffectDropShadow* effect, const Matrix& transform)
|
||||||
|
{
|
||||||
|
GlDropShadow* dropShadow = (GlDropShadow*)effect->rd;
|
||||||
|
if (!dropShadow) dropShadow = tvg::malloc<GlDropShadow*>(sizeof(GlDropShadow));
|
||||||
|
const float sigma = effect->sigma;
|
||||||
|
const float scale = std::sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12);
|
||||||
|
const float radian = tvg::deg2rad(90.0f - effect->angle);
|
||||||
|
const Point offset = {
|
||||||
|
-effect->distance * cosf(radian) * scale,
|
||||||
|
-effect->distance * sinf(radian) * scale
|
||||||
|
};
|
||||||
|
dropShadow->sigma = sigma;
|
||||||
|
dropShadow->scale = scale;
|
||||||
|
dropShadow->level = int(GL_GAUSSIAN_MAX_LEVEL * ((effect->quality - 1) * 0.01f)) + 1;
|
||||||
|
dropShadow->color[0] = effect->color[0] / 255.0f;
|
||||||
|
dropShadow->color[1] = effect->color[1] / 255.0f;
|
||||||
|
dropShadow->color[2] = effect->color[2] / 255.0f;
|
||||||
|
dropShadow->color[3] = effect->color[3] / 255.0f;
|
||||||
|
dropShadow->offset[0] = offset.x;
|
||||||
|
dropShadow->offset[1] = offset.y;
|
||||||
|
dropShadow->extend = 2 * std::max(sigma * scale + std::abs(offset.x), sigma * scale + std::abs(offset.y));
|
||||||
|
effect->rd = dropShadow;
|
||||||
|
effect->valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GlRenderer::effectFillUpdate(RenderEffectFill* effect, const Matrix& transform)
|
void GlRenderer::effectFillUpdate(RenderEffectFill* effect, const Matrix& transform)
|
||||||
{
|
{
|
||||||
auto params = (GlEffectParams*)effect->rd;
|
auto params = (GlEffectParams*)effect->rd;
|
||||||
|
@ -1031,6 +1058,17 @@ bool GlRenderer::effectGaussianBlurRegion(RenderEffectGaussianBlur* effect)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool GlRenderer::effectDropShadowRegion(RenderEffectDropShadow* effect)
|
||||||
|
{
|
||||||
|
auto gaussianBlur = (GlDropShadow*)effect->rd;
|
||||||
|
effect->extend.x = -gaussianBlur->extend;
|
||||||
|
effect->extend.w = +gaussianBlur->extend * 2;
|
||||||
|
effect->extend.y = -gaussianBlur->extend;
|
||||||
|
effect->extend.h = +gaussianBlur->extend * 2;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void GlRenderer::prepare(RenderEffect* effect, const Matrix& transform)
|
void GlRenderer::prepare(RenderEffect* effect, const Matrix& transform)
|
||||||
{
|
{
|
||||||
// we must be sure, that we have intermidiate FBOs
|
// we must be sure, that we have intermidiate FBOs
|
||||||
|
@ -1039,6 +1077,7 @@ void GlRenderer::prepare(RenderEffect* effect, const Matrix& transform)
|
||||||
|
|
||||||
switch (effect->type) {
|
switch (effect->type) {
|
||||||
case SceneEffect::GaussianBlur: effectGaussianBlurUpdate(static_cast<RenderEffectGaussianBlur*>(effect), transform); break;
|
case SceneEffect::GaussianBlur: effectGaussianBlurUpdate(static_cast<RenderEffectGaussianBlur*>(effect), transform); break;
|
||||||
|
case SceneEffect::DropShadow : effectDropShadowUpdate(static_cast<RenderEffectDropShadow*>(effect), transform); break;
|
||||||
case SceneEffect::Fill: effectFillUpdate(static_cast<RenderEffectFill*>(effect), transform); break;
|
case SceneEffect::Fill: effectFillUpdate(static_cast<RenderEffectFill*>(effect), transform); break;
|
||||||
case SceneEffect::Tint: effectTintUpdate(static_cast<RenderEffectTint*>(effect), transform); break;
|
case SceneEffect::Tint: effectTintUpdate(static_cast<RenderEffectTint*>(effect), transform); break;
|
||||||
case SceneEffect::Tritone: effectTritoneUpdate(static_cast<RenderEffectTritone*>(effect), transform); break;
|
case SceneEffect::Tritone: effectTritoneUpdate(static_cast<RenderEffectTritone*>(effect), transform); break;
|
||||||
|
@ -1052,6 +1091,7 @@ bool GlRenderer::region(RenderEffect* effect)
|
||||||
{
|
{
|
||||||
switch (effect->type) {
|
switch (effect->type) {
|
||||||
case SceneEffect::GaussianBlur: return effectGaussianBlurRegion(static_cast<RenderEffectGaussianBlur*>(effect));
|
case SceneEffect::GaussianBlur: return effectGaussianBlurRegion(static_cast<RenderEffectGaussianBlur*>(effect));
|
||||||
|
case SceneEffect::DropShadow : return effectDropShadowRegion(static_cast<RenderEffectDropShadow*>(effect));
|
||||||
case SceneEffect::Fill:
|
case SceneEffect::Fill:
|
||||||
case SceneEffect::Tint:
|
case SceneEffect::Tint:
|
||||||
case SceneEffect::Tritone: return true;
|
case SceneEffect::Tritone: return true;
|
||||||
|
@ -1074,6 +1114,7 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
|
||||||
auto voffset = mGpuBuffer.push((void*)vdata, sizeof(vdata));
|
auto voffset = mGpuBuffer.push((void*)vdata, sizeof(vdata));
|
||||||
auto ioffset = mGpuBuffer.pushIndex((void*)idata, sizeof(idata));
|
auto ioffset = mGpuBuffer.pushIndex((void*)idata, sizeof(idata));
|
||||||
|
|
||||||
|
// effect gaussian blur
|
||||||
if (effect->type == SceneEffect::GaussianBlur) {
|
if (effect->type == SceneEffect::GaussianBlur) {
|
||||||
// get gaussian programs
|
// get gaussian programs
|
||||||
GlProgram* programHorz = mPrograms[RT_GaussianHorz];
|
GlProgram* programHorz = mPrograms[RT_GaussianHorz];
|
||||||
|
@ -1102,7 +1143,40 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
|
||||||
gaussianTask->vertTask->setDrawRange(ioffset, 6);
|
gaussianTask->vertTask->setDrawRange(ioffset, 6);
|
||||||
// add task to render pipeline
|
// add task to render pipeline
|
||||||
pass->addRenderTask(gaussianTask);
|
pass->addRenderTask(gaussianTask);
|
||||||
} // effect fill
|
} // effect drop shadow
|
||||||
|
else if (effect->type == SceneEffect::DropShadow) {
|
||||||
|
// get programs
|
||||||
|
GlProgram* program = mPrograms[RT_DropShadow];
|
||||||
|
GlProgram* programHorz = mPrograms[RT_GaussianHorz];
|
||||||
|
GlProgram* programVert = mPrograms[RT_GaussianVert];
|
||||||
|
// get current and intermidiate framebuffers
|
||||||
|
auto dstFbo = pass->getFbo();
|
||||||
|
auto dstCopyFbo0 = mBlendPool[0]->getRenderTarget(vp);
|
||||||
|
auto dstCopyFbo1 = mBlendPool[1]->getRenderTarget(vp);
|
||||||
|
// add uniform data
|
||||||
|
GlDropShadow* params = (GlDropShadow*)(effect->rd);
|
||||||
|
auto paramsOffset = mGpuBuffer.push(params, sizeof(GlDropShadow), true);
|
||||||
|
|
||||||
|
// create gaussian blur tasks
|
||||||
|
auto task = new GlEffectDropShadowTask(program, dstFbo, dstCopyFbo0, dstCopyFbo1);
|
||||||
|
task->effect = (RenderEffectDropShadow*)effect;
|
||||||
|
task->setViewport({0, 0, vp.w, vp.h});
|
||||||
|
task->addBindResource(GlBindingResource{0, program->getUniformBlockIndex("DropShadow"), mGpuBuffer.getBufferId(), paramsOffset, sizeof(GlDropShadow)});
|
||||||
|
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
|
||||||
|
task->setDrawRange(ioffset, 6);
|
||||||
|
// horizontal blur task and geometry
|
||||||
|
task->horzTask = new GlRenderTask(programHorz);
|
||||||
|
task->horzTask->addBindResource(GlBindingResource{0, programHorz->getUniformBlockIndex("Gaussian"), mGpuBuffer.getBufferId(), paramsOffset, sizeof(GlGaussianBlur)});
|
||||||
|
task->horzTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
|
||||||
|
task->horzTask->setDrawRange(ioffset, 6);
|
||||||
|
// vertical blur task and geometry
|
||||||
|
task->vertTask = new GlRenderTask(programVert);
|
||||||
|
task->vertTask->addBindResource(GlBindingResource{0, programVert->getUniformBlockIndex("Gaussian"), mGpuBuffer.getBufferId(), paramsOffset, sizeof(GlGaussianBlur)});
|
||||||
|
task->vertTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
|
||||||
|
task->vertTask->setDrawRange(ioffset, 6);
|
||||||
|
// add task to render pipeline
|
||||||
|
pass->addRenderTask(task);
|
||||||
|
} // effect fill, tint, tritone
|
||||||
else if ((effect->type == SceneEffect::Fill) || (effect->type == SceneEffect::Tint) || (effect->type == SceneEffect::Tritone)) {
|
else if ((effect->type == SceneEffect::Fill) || (effect->type == SceneEffect::Tint) || (effect->type == SceneEffect::Tritone)) {
|
||||||
GlProgram* program{};
|
GlProgram* program{};
|
||||||
if (effect->type == SceneEffect::Fill) program = mPrograms[RT_EffectFill];
|
if (effect->type == SceneEffect::Fill) program = mPrograms[RT_EffectFill];
|
||||||
|
|
|
@ -62,7 +62,7 @@ public:
|
||||||
|
|
||||||
RT_GaussianVert,
|
RT_GaussianVert,
|
||||||
RT_GaussianHorz,
|
RT_GaussianHorz,
|
||||||
//RT_DropShadow,
|
RT_DropShadow,
|
||||||
RT_EffectFill,
|
RT_EffectFill,
|
||||||
RT_EffectTint,
|
RT_EffectTint,
|
||||||
RT_EffectTritone,
|
RT_EffectTritone,
|
||||||
|
@ -124,11 +124,13 @@ private:
|
||||||
void endRenderPass(RenderCompositor* cmp);
|
void endRenderPass(RenderCompositor* cmp);
|
||||||
|
|
||||||
void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform);
|
void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform);
|
||||||
|
void effectDropShadowUpdate(RenderEffectDropShadow* effect, const Matrix& transform);
|
||||||
void effectFillUpdate(RenderEffectFill* effect, const Matrix& transform);
|
void effectFillUpdate(RenderEffectFill* effect, const Matrix& transform);
|
||||||
void effectTintUpdate(RenderEffectTint* effect, const Matrix& transform);
|
void effectTintUpdate(RenderEffectTint* effect, const Matrix& transform);
|
||||||
void effectTritoneUpdate(RenderEffectTritone* effect, const Matrix& transform);
|
void effectTritoneUpdate(RenderEffectTritone* effect, const Matrix& transform);
|
||||||
|
|
||||||
bool effectGaussianBlurRegion(RenderEffectGaussianBlur* effect);
|
bool effectGaussianBlurRegion(RenderEffectGaussianBlur* effect);
|
||||||
|
bool effectDropShadowRegion(RenderEffectDropShadow* effect);
|
||||||
|
|
||||||
void flush();
|
void flush();
|
||||||
void clearDisposes();
|
void clearDisposes();
|
||||||
|
|
|
@ -821,6 +821,32 @@ void main()
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
const char* EFFECT_DROPSHADOW = R"(
|
||||||
|
uniform sampler2D uSrcTexture;
|
||||||
|
uniform sampler2D uBlrTexture;
|
||||||
|
layout(std140) uniform DropShadow {
|
||||||
|
int level;
|
||||||
|
float sigma;
|
||||||
|
float scale;
|
||||||
|
float extend;
|
||||||
|
vec4 color;
|
||||||
|
vec2 offset;
|
||||||
|
} uDropShadow;
|
||||||
|
|
||||||
|
in vec2 vUV;
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 texelSize = 1.0 / vec2(textureSize(uSrcTexture, 0));
|
||||||
|
vec2 offset = uDropShadow.offset * texelSize;
|
||||||
|
vec4 orig = texture(uSrcTexture, vUV);
|
||||||
|
vec4 blur = texture(uBlrTexture, vUV + offset);
|
||||||
|
vec4 shad = uDropShadow.color * blur.a;
|
||||||
|
FragColor = orig + shad * (1.0 - orig.a);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
const char* EFFECT_FILL = R"(
|
const char* EFFECT_FILL = R"(
|
||||||
uniform sampler2D uSrcTexture;
|
uniform sampler2D uSrcTexture;
|
||||||
layout(std140) uniform Params {
|
layout(std140) uniform Params {
|
||||||
|
|
|
@ -57,6 +57,7 @@ extern const char* EXCLUSION_BLEND_FRAG;
|
||||||
extern const char* EFFECT_VERTEX;
|
extern const char* EFFECT_VERTEX;
|
||||||
extern const char* GAUSSIAN_VERTICAL;
|
extern const char* GAUSSIAN_VERTICAL;
|
||||||
extern const char* GAUSSIAN_HORIZONTAL;
|
extern const char* GAUSSIAN_HORIZONTAL;
|
||||||
|
extern const char* EFFECT_DROPSHADOW;
|
||||||
extern const char* EFFECT_FILL;
|
extern const char* EFFECT_FILL;
|
||||||
extern const char* EFFECT_TINT;
|
extern const char* EFFECT_TINT;
|
||||||
extern const char* EFFECT_TRITONE;
|
extern const char* EFFECT_TRITONE;
|
||||||
|
|
Loading…
Add table
Reference in a new issue