summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/runtime/q3dsdistancefieldmaterialgenerator.cpp14
-rw-r--r--src/runtime/q3dsdistancefieldmaterialgenerator_p.h3
-rw-r--r--src/runtime/q3dsres.qrc4
-rw-r--r--src/runtime/q3dsscenemanager.cpp84
-rw-r--r--src/runtime/q3dsscenemanager_p.h1
-rw-r--r--src/runtime/q3dstextmesh.cpp36
-rw-r--r--src/runtime/q3dstextmesh_p.h3
-rw-r--r--src/runtime/shaders/distancefieldtext_dropshadow.frag29
-rw-r--r--src/runtime/shaders/distancefieldtext_dropshadow.vert75
-rw-r--r--src/runtime/shaders/distancefieldtext_dropshadow_core.frag34
-rw-r--r--src/runtime/shaders/distancefieldtext_dropshadow_core.vert55
11 files changed, 310 insertions, 28 deletions
diff --git a/src/runtime/q3dsdistancefieldmaterialgenerator.cpp b/src/runtime/q3dsdistancefieldmaterialgenerator.cpp
index 8dacef1..abb1b4d 100644
--- a/src/runtime/q3dsdistancefieldmaterialgenerator.cpp
+++ b/src/runtime/q3dsdistancefieldmaterialgenerator.cpp
@@ -42,7 +42,8 @@
QT_BEGIN_NAMESPACE
-Qt3DRender::QMaterial *Q3DSDistanceFieldMaterialGenerator::generateMaterial(const QVector<Qt3DRender::QParameter *> &params)
+Qt3DRender::QMaterial *Q3DSDistanceFieldMaterialGenerator::generateMaterial(const QVector<Qt3DRender::QParameter *> &params,
+ bool dropShadow)
{
Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial;
Qt3DRender::QEffect *effect = new Qt3DRender::QEffect;
@@ -53,13 +54,10 @@ Qt3DRender::QMaterial *Q3DSDistanceFieldMaterialGenerator::generateMaterial(cons
Q3DSDefaultMaterialGenerator::addDefaultApiFilter(technique, &isGLES);
Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram;
- if (isGLES) {
- shaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QLatin1String("qrc:/q3ds/shaders/distancefieldtext.vert"))));
- shaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QLatin1String("qrc:/q3ds/shaders/distancefieldtext.frag"))));
- } else {
- shaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QLatin1String("qrc:/q3ds/shaders/distancefieldtext_core.vert"))));
- shaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QLatin1String("qrc:/q3ds/shaders/distancefieldtext_core.frag"))));
- }
+
+ QString name = QStringLiteral("distancefieldtext") + (dropShadow ? QStringLiteral("_dropshadow") : QString()) + (!isGLES ? QStringLiteral("_core") : QString());
+ shaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/q3ds/shaders/") + name + QStringLiteral(".vert"))));
+ shaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/q3ds/shaders/") + name + QStringLiteral(".frag"))));
Qt3DRender::QRenderPass *renderPass = new Qt3DRender::QRenderPass;
Qt3DRender::QFilterKey *transFilterKey = new Qt3DRender::QFilterKey;
diff --git a/src/runtime/q3dsdistancefieldmaterialgenerator_p.h b/src/runtime/q3dsdistancefieldmaterialgenerator_p.h
index bb85c73..07ef527 100644
--- a/src/runtime/q3dsdistancefieldmaterialgenerator_p.h
+++ b/src/runtime/q3dsdistancefieldmaterialgenerator_p.h
@@ -55,7 +55,8 @@ class QMaterial;
class Q3DSDistanceFieldMaterialGenerator
{
public:
- Qt3DRender::QMaterial *generateMaterial(const QVector<Qt3DRender::QParameter *> &params);
+ Qt3DRender::QMaterial *generateMaterial(const QVector<Qt3DRender::QParameter *> &params,
+ bool dropShadow);
};
QT_END_NAMESPACE
diff --git a/src/runtime/q3dsres.qrc b/src/runtime/q3dsres.qrc
index e70f636..0c20267 100644
--- a/src/runtime/q3dsres.qrc
+++ b/src/runtime/q3dsres.qrc
@@ -132,5 +132,9 @@
<file alias="res/effectlib/gles2/shadowMapping.glsllib">../../res/effectlib/gles2/shadowMapping.glsllib</file>
<file alias="res/effectlib/gles2/SSAOCustomMaterial.glsllib">../../res/effectlib/gles2/SSAOCustomMaterial.glsllib</file>
<file alias="res/effectlib/gles2/tangentSpaceNormalTexture.glsllib">../../res/effectlib/gles2/tangentSpaceNormalTexture.glsllib</file>
+ <file>shaders/distancefieldtext_dropshadow_core.vert</file>
+ <file>shaders/distancefieldtext_dropshadow_core.frag</file>
+ <file>shaders/distancefieldtext_dropshadow.frag</file>
+ <file>shaders/distancefieldtext_dropshadow.vert</file>
</qresource>
</RCC>
diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp
index d6f909c..8dc7aa2 100644
--- a/src/runtime/q3dsscenemanager.cpp
+++ b/src/runtime/q3dsscenemanager.cpp
@@ -4761,10 +4761,9 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
}
#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
- static bool distanceFieldRendering = distanceFieldsEnabled();
+ static bool shouldDistanceFieldRender = distanceFieldsEnabled();
- bool shouldDistanceFieldRender = distanceFieldRendering && !text3DS->shadow();
- if (data->entity != nullptr && shouldDistanceFieldRender != data->distanceFieldText) {
+ if (data->entity != nullptr && text3DS->shadow() != data->dropShadow) {
for (int i = 0; i < data->glyphsReferencedInSubentity.size(); ++i) {
QPair<Q3DSDistanceFieldGlyphCache *, QVector<quint32> > &glyphsReferenced = data->glyphsReferencedInSubentity[i];
if (glyphsReferenced.first != nullptr && !glyphsReferenced.second.isEmpty())
@@ -4791,6 +4790,7 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
if (shouldDistanceFieldRender) {
data->distanceFieldText = true;
+ data->dropShadow = text3DS->shadow();
QVector2D boundingBox = text3DS->boundingBox();
QRawFont font = m_fontDatabase->findFont(text3DS->font());
@@ -4969,6 +4969,8 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
QVector<quint32> glyphIndexes;
Q3DSDistanceFieldGlyphCache *cache;
float fontScale;
+ float shadowOffsetX;
+ float shadowOffsetY;
};
QHash<Q3DSDistanceFieldGlyphCache::TextureInfo *, GlyphInfo> glyphsPerTexture;
@@ -5021,6 +5023,8 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
cache->processPendingGlyphs();
qreal fontPixelSize = glyphRun.rawFont().pixelSize();
+ float shadowOffsetX = float(fontPixelSize) * text3DS->shadowOffsetX() / 1000.0f;
+ float shadowOffsetY = float(fontPixelSize) * text3DS->shadowOffsetY() / 1000.0f;
qreal maxTexMargin = cache->distanceFieldRadius();
qreal fontScale = cache->fontScale(fontPixelSize);
qreal margin = 2;
@@ -5056,11 +5060,24 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
float cy1 = float(position.y() - metrics.baselineY) + offsetY;
float cy2 = cy1 + float(metrics.height);
+ if (text3DS->shadow()) {
+ cx2 += shadowOffsetX;
+ cy2 += shadowOffsetY;
+ }
+
float tx1 = float(c.x + c.xMargin);
float tx2 = tx1 + float(c.width);
float ty1 = float(c.y + c.yMargin);
float ty2 = ty1 + float(c.height);
+ float ttx2 = tx2;
+ float tty2 = ty2;
+
+ if (text3DS->shadow()) {
+ tx2 += float(c.width) * shadowOffsetX / float(metrics.width);
+ ty2 += float(c.height) * shadowOffsetY / float(metrics.height);
+ }
+
const QSGDistanceFieldGlyphCache::Texture *texture = cache->glyphTexture(glyphIndex);
if (texture->textureId == 0) {
qWarning() << "Empty texture for glyph" << glyphIndex;
@@ -5071,9 +5088,11 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
GlyphInfo &glyphInfo = glyphsPerTexture[textureInfo];
glyphInfo.fontScale = float(fontScale);
+ glyphInfo.shadowOffsetX = shadowOffsetX;
+ glyphInfo.shadowOffsetY = shadowOffsetY;
QVector<float> &vertexes = glyphInfo.vertexes;
- vertexes.reserve(vertexes.size() + 10);
+ vertexes.reserve(vertexes.size() + 20 + (text3DS->shadow() ? 16 : 0));
vertexes.append(cx1);
vertexes.append(0.0);
@@ -5081,23 +5100,51 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
vertexes.append(tx1);
vertexes.append(ty1);
+ if (text3DS->shadow()) {
+ vertexes.append(tx1);
+ vertexes.append(ty1);
+ vertexes.append(ttx2);
+ vertexes.append(tty2);
+ }
+
vertexes.append(cx2);
vertexes.append(0.0);
vertexes.append(cy1);
vertexes.append(tx2);
vertexes.append(ty1);
+ if (text3DS->shadow()) {
+ vertexes.append(tx1);
+ vertexes.append(ty1);
+ vertexes.append(ttx2);
+ vertexes.append(tty2);
+ }
+
vertexes.append(cx2);
vertexes.append(0.0);
vertexes.append(cy2);
vertexes.append(tx2);
vertexes.append(ty2);
+ if (text3DS->shadow()) {
+ vertexes.append(tx1);
+ vertexes.append(ty1);
+ vertexes.append(ttx2);
+ vertexes.append(tty2);
+ }
+
vertexes.append(cx1);
vertexes.append(0.0);
vertexes.append(cy2);
vertexes.append(tx1);
vertexes.append(ty2);
+
+ if (text3DS->shadow()) {
+ vertexes.append(tx1);
+ vertexes.append(ty1);
+ vertexes.append(ttx2);
+ vertexes.append(tty2);
+ }
}
}
}
@@ -5140,11 +5187,23 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
Qt3DRender::QParameter *fontScaleParam = new Qt3DRender::QParameter;
fontScaleParam->setName(QLatin1String("fontScale"));
- Qt3DRender::QMaterial *material = m_distanceFieldMaterialGenerator->generateMaterial({ colorParam,
- textureParam,
- fontScaleParam,
- textureWidthParam,
- textureHeightParam });
+ QVector<Qt3DRender::QParameter *> params = { colorParam,
+ textureParam,
+ fontScaleParam,
+ textureWidthParam,
+ textureHeightParam };
+
+ if (text3DS->shadow()) {
+ Qt3DRender::QParameter *shadowColorParam = new Qt3DRender::QParameter;
+ shadowColorParam->setName(QLatin1String("shadowColor"));
+ params.append(shadowColorParam);
+
+ Qt3DRender::QParameter *shadowOffsetParam = new Qt3DRender::QParameter;
+ shadowOffsetParam->setName(QLatin1String("shadowOffset"));
+ params.append(shadowOffsetParam);
+ }
+
+ Qt3DRender::QMaterial *material = m_distanceFieldMaterialGenerator->generateMaterial(params, text3DS->shadow());
subentity->addComponent(material);
subentities.append(subentity);
}
@@ -5152,6 +5211,7 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
QHash<Q3DSDistanceFieldGlyphCache::TextureInfo *, GlyphInfo>::const_iterator it;
int subentityIndex = 0;
+ int shadowRgb = int(2.55f * (100 - int(text3DS->shadowStrength())));
for (it = glyphsPerTexture.constBegin(); it != glyphsPerTexture.constEnd(); ++it) {
const GlyphInfo &glyphInfo = it.value();
const QVector<float> &vertexes = glyphInfo.vertexes;
@@ -5168,7 +5228,7 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
{
Q3DSTextMesh *mesh = qobject_cast<Q3DSTextMesh *>(component);
if (mesh != nullptr)
- mesh->setVertexes(vertexes);
+ mesh->setVertexes(vertexes, text3DS->shadow());
}
{
@@ -5184,6 +5244,10 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN
parameter->setValue(color * data->globalOpacity);
data->colorParam.append(parameter);
+ } else if (parameter->name() == QLatin1String("shadowColor")) {
+ parameter->setValue(QColor(shadowRgb, shadowRgb, shadowRgb));
+ } else if (parameter->name() == QLatin1String("shadowOffset")) {
+ parameter->setValue(QVector2D(glyphInfo.shadowOffsetX, glyphInfo.shadowOffsetY));
} else if (parameter->name() == QLatin1String("_qt_texture")) {
parameter->setValue(QVariant::fromValue(it.key()->texture));
} else if (parameter->name() == QLatin1String("fontScale")) {
diff --git a/src/runtime/q3dsscenemanager_p.h b/src/runtime/q3dsscenemanager_p.h
index d1a4461..5cdb806 100644
--- a/src/runtime/q3dsscenemanager_p.h
+++ b/src/runtime/q3dsscenemanager_p.h
@@ -456,6 +456,7 @@ class Q3DSTextAttached : public Q3DSNodeAttached
{
public:
bool distanceFieldText = false;
+ bool dropShadow = false;
Qt3DExtras::QPlaneMesh *mesh = nullptr;
Qt3DRender::QParameter *opacityParam = nullptr;
QVector<Qt3DRender::QParameter *> colorParam;
diff --git a/src/runtime/q3dstextmesh.cpp b/src/runtime/q3dstextmesh.cpp
index 13fc8dd..4290204 100644
--- a/src/runtime/q3dstextmesh.cpp
+++ b/src/runtime/q3dstextmesh.cpp
@@ -64,30 +64,34 @@ namespace {
class Q3DSTextMeshGeometry : public Qt3DRender::QGeometry
{
public:
- Q3DSTextMeshGeometry(const QVector<float> &vertexes, Qt3DCore::QNode *parent = nullptr);
+ Q3DSTextMeshGeometry(bool shadow,
+ const QVector<float> &vertexes,
+ Qt3DCore::QNode *parent = nullptr);
private:
Qt3DRender::QBuffer *m_vertexBuffer;
Qt3DRender::QBuffer *m_indexBuffer;
Qt3DRender::QAttribute *m_positionAttribute;
Qt3DRender::QAttribute *m_textureCoordinateAttribute;
Qt3DRender::QAttribute *m_indexAttribute;
+ Qt3DRender::QAttribute *m_textureBoundsAttribute;
};
- Q3DSTextMeshGeometry::Q3DSTextMeshGeometry(const QVector<float> &vertexes,
+ Q3DSTextMeshGeometry::Q3DSTextMeshGeometry(bool shadow,
+ const QVector<float> &vertexes,
Qt3DCore::QNode *parent)
: Qt3DRender::QGeometry(parent)
{
- Q_ASSERT(vertexes.size() % 10 == 0);
-
m_vertexBuffer = new Qt3DRender::QBuffer(this);
m_vertexBuffer->setUsage(Qt3DRender::QBuffer::StaticDraw);
m_vertexBuffer->setAccessType(Qt3DRender::QBuffer::Read);
m_vertexBuffer->setData(QByteArray(reinterpret_cast<const char *>(vertexes.constData()),
int(vertexes.size() * sizeof(float))));
- const uint stride = (3 + 2) * sizeof(float);
+ const uint floatsPerVertex = shadow ? 3 + 2 + 4 : 3 + 2;
+ const uint stride = floatsPerVertex * sizeof(float);
- const uint vertexCount = uint(vertexes.size() / 5);
+ Q_ASSERT(uint(vertexes.size()) % floatsPerVertex == 0);
+ const uint vertexCount = uint(vertexes.size()) / floatsPerVertex;
Q_ASSERT(vertexCount % 4 == 0);
const uint quadCount = vertexCount / 4;
@@ -125,6 +129,20 @@ namespace {
m_textureCoordinateAttribute->setByteOffset(3 * sizeof(float));
m_textureCoordinateAttribute->setCount(vertexCount);
+ if (shadow) {
+ m_textureBoundsAttribute = new Qt3DRender::QAttribute(this);
+ m_textureBoundsAttribute->setName(QStringLiteral("textureBounds"));
+ m_textureBoundsAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ m_textureBoundsAttribute->setVertexSize(4);
+ m_textureBoundsAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+ m_textureBoundsAttribute->setBuffer(m_vertexBuffer);
+ m_textureBoundsAttribute->setByteStride(stride);
+ m_textureBoundsAttribute->setByteOffset(5 * sizeof(float));
+ m_textureBoundsAttribute->setCount(vertexCount);
+ } else {
+ m_textureBoundsAttribute = nullptr;
+ }
+
m_indexAttribute = new Qt3DRender::QAttribute(this);
m_indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
m_indexAttribute->setVertexBaseType(indexType);
@@ -134,6 +152,8 @@ namespace {
addAttribute(m_positionAttribute);
addAttribute(m_textureCoordinateAttribute);
addAttribute(m_indexAttribute);
+ if (shadow)
+ addAttribute(m_textureBoundsAttribute);
}
}
@@ -143,10 +163,10 @@ Q3DSTextMesh::Q3DSTextMesh(Qt3DCore::QNode *parent)
{
}
-void Q3DSTextMesh::setVertexes(const QVector<float> &vertexes)
+void Q3DSTextMesh::setVertexes(const QVector<float> &vertexes, bool dropShadow)
{
delete m_geometry;
- m_geometry = new Q3DSTextMeshGeometry(vertexes, this);
+ m_geometry = new Q3DSTextMeshGeometry(dropShadow, vertexes, this);
setGeometry(m_geometry);
}
diff --git a/src/runtime/q3dstextmesh_p.h b/src/runtime/q3dstextmesh_p.h
index 69b07a3..b68ecc9 100644
--- a/src/runtime/q3dstextmesh_p.h
+++ b/src/runtime/q3dstextmesh_p.h
@@ -56,7 +56,8 @@ public:
explicit Q3DSTextMesh(Qt3DCore::QNode *parent = nullptr);
~Q3DSTextMesh() override;
- void setVertexes(const QVector<float> &vertexes);
+ void setVertexes(const QVector<float> &vertexes,
+ bool dropShadow);
private:
Qt3DRender::QGeometry *m_geometry;
diff --git a/src/runtime/shaders/distancefieldtext_dropshadow.frag b/src/runtime/shaders/distancefieldtext_dropshadow.frag
new file mode 100644
index 0000000..da51c5c
--- /dev/null
+++ b/src/runtime/shaders/distancefieldtext_dropshadow.frag
@@ -0,0 +1,29 @@
+varying highp vec2 sampleCoord;
+varying highp vec2 alphas;
+varying highp vec2 shadowSampleCoord;
+varying highp vec4 normalizedTextureBounds;
+
+uniform sampler2D _qt_texture;
+uniform highp vec4 color;
+uniform highp vec4 shadowColor;
+
+void main()
+{
+ highp float shadowAlpha = smoothstep(alphas.x,
+ alphas.y,
+ texture2D(_qt_texture,
+ clamp(shadowSampleCoord,
+ normalizedTextureBounds.xy,
+ normalizedTextureBounds.zw)).a);
+ highp vec4 shadowPixel = shadowColor * shadowAlpha;
+
+ highp float textAlpha = smoothstep(alphas.x,
+ alphas.y,
+ texture2D(_qt_texture,
+ clamp(sampleCoord,
+ normalizedTextureBounds.xy,
+ normalizedTextureBounds.zw)).a);
+ highp vec4 textPixel = color * textAlpha;
+
+ gl_FragColor = mix(shadowPixel, textPixel, textPixel.a);
+}
diff --git a/src/runtime/shaders/distancefieldtext_dropshadow.vert b/src/runtime/shaders/distancefieldtext_dropshadow.vert
new file mode 100644
index 0000000..69fd211
--- /dev/null
+++ b/src/runtime/shaders/distancefieldtext_dropshadow.vert
@@ -0,0 +1,75 @@
+uniform highp mat4 mvp;
+uniform highp mat4 modelView;
+uniform highp float fontScale;
+uniform int textureWidth;
+uniform int textureHeight;
+uniform highp vec2 shadowOffset;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+attribute highp vec4 textureBounds;
+
+varying highp vec2 sampleCoord;
+varying highp vec2 shadowSampleCoord;
+varying highp vec2 alphas;
+varying highp vec4 normalizedTextureBounds;
+
+highp float thresholdFunc(highp float scale)
+{
+ highp float base = 0.5;
+ highp float baseDev = 0.065;
+ highp float devScaleMin = 0.15;
+ highp float devScaleMax = 0.3;
+ return base - ((clamp(scale, devScaleMin, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev);
+}
+
+highp float spreadFunc(highp float scale)
+{
+ return 0.06 / scale;
+}
+
+highp vec2 alphaRange(highp float scale)
+{
+ highp float base = thresholdFunc(scale);
+ highp float range = spreadFunc(scale);
+ highp float alphaMin = max(0.0, base - range);
+ highp float alphaMax = min(base + range, 1.0);
+ return highp vec2(alphaMin, alphaMax);
+}
+
+highp float determinantOfSubmatrix(highp mat4 m, int col0, int col1, int row0, int row1)
+{
+ return m[col0][row0] * m[col1][row1] - m[col0][row1] * m[col1][row0];
+}
+
+highp float determinantOfSubmatrix(highp mat4 m, int col0, int col1, int col2, int row0, int row1, int row2)
+{
+ highp float det = m[col0][row0] * determinantOfSubmatrix(m, col1, col2, row1, row2);
+ det -= m[col1][row0] * determinantOfSubmatrix(m, col0, col2, row1, row2);
+ det += m[col2][row0] * determinantOfSubmatrix(m, col0, col1, row1, row2);
+ return det;
+}
+
+highp float determinant(highp mat4 m)
+{
+ highp float det = m[0][0] * determinantOfSubmatrix(m, 1, 2, 3, 1, 2, 3);
+ det -= m[1][0] * determinantOfSubmatrix(m, 0, 2, 3, 1, 2, 3);
+ det += m[2][0] * determinantOfSubmatrix(m, 0, 1, 3, 1, 2, 3);
+ det -= m[3][0] * determinantOfSubmatrix(m, 0, 1, 2, 1, 2, 3);
+ return det;
+}
+
+void main()
+{
+ highp float scale = fontScale * sqrt(abs(determinant(modelView)));
+ alphas = alphaRange(scale);
+
+ highp vec2 textureSizeMultiplier = highp vec2(1.0 / highp float(textureWidth), 1.0 / highp float(textureHeight));
+
+ sampleCoord = tCoord * textureSizeMultiplier;
+ shadowSampleCoord = (tCoord - shadowOffset) * textureSizeMultiplier;
+ normalizedTextureBounds = highp vec4(textureBounds.xy * textureSizeMultiplier,
+ textureBounds.zw * textureSizeMultiplier);
+
+ gl_Position = mvp * vCoord;
+}
diff --git a/src/runtime/shaders/distancefieldtext_dropshadow_core.frag b/src/runtime/shaders/distancefieldtext_dropshadow_core.frag
new file mode 100644
index 0000000..46a1194
--- /dev/null
+++ b/src/runtime/shaders/distancefieldtext_dropshadow_core.frag
@@ -0,0 +1,34 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec2 shadowSampleCoord;
+in vec4 normalizedTextureBounds;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 shadowColor;
+
+in vec2 alphas;
+
+void main()
+{
+ float shadowAlpha = smoothstep(alphas.x,
+ alphas.y,
+ texture(_qt_texture,
+ clamp(shadowSampleCoord,
+ normalizedTextureBounds.xy,
+ normalizedTextureBounds.zw)).r);
+ vec4 shadowPixel = shadowColor * shadowAlpha;
+
+ float textAlpha = smoothstep(alphas.x,
+ alphas.y,
+ texture(_qt_texture,
+ clamp(sampleCoord,
+ normalizedTextureBounds.xy,
+ normalizedTextureBounds.zw)).r);
+ vec4 textPixel = color * textAlpha;
+
+ fragColor = mix(shadowPixel, textPixel, textPixel.a);
+}
diff --git a/src/runtime/shaders/distancefieldtext_dropshadow_core.vert b/src/runtime/shaders/distancefieldtext_dropshadow_core.vert
new file mode 100644
index 0000000..727dac5
--- /dev/null
+++ b/src/runtime/shaders/distancefieldtext_dropshadow_core.vert
@@ -0,0 +1,55 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+in vec4 textureBounds;
+
+out vec2 sampleCoord;
+out vec2 shadowSampleCoord;
+
+out vec2 alphas;
+out vec4 normalizedTextureBounds;
+
+uniform mat4 mvp;
+uniform mat4 modelView;
+uniform int textureWidth;
+uniform int textureHeight;
+uniform float fontScale;
+uniform vec2 shadowOffset;
+
+float thresholdFunc(float scale)
+{
+ float base = 0.5;
+ float baseDev = 0.065;
+ float devScaleMin = 0.15;
+ float devScaleMax = 0.3;
+ return base - ((clamp(scale, devScaleMin, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev);
+}
+
+float spreadFunc(float scale)
+{
+ return 0.06 / scale;
+}
+
+vec2 alphaRange(float scale)
+{
+ float base = thresholdFunc(scale);
+ float range = spreadFunc(scale);
+ float alphaMin = max(0.0, base - range);
+ float alphaMax = min(base + range, 1.0);
+ return vec2(alphaMin, alphaMax);
+}
+
+void main()
+{
+ float scale = fontScale * sqrt(abs(determinant(modelView)));
+ alphas = alphaRange(scale);
+
+ vec2 textureSizeMultiplier = vec2(1.0 / textureWidth, 1.0 / textureHeight);
+
+ sampleCoord = tCoord * textureSizeMultiplier;
+ shadowSampleCoord = (tCoord - shadowOffset) * textureSizeMultiplier;
+ normalizedTextureBounds = vec4(textureBounds.xy * textureSizeMultiplier,
+ textureBounds.zw * textureSizeMultiplier);
+ gl_Position = mvp * vCoord;
+}