Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / qsgdistancefieldglyphnode_p.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsgdistancefieldglyphnode_p_p.h"
43 #include <QtQuick/private/qsgdistancefieldutil_p.h>
44 #include <QtQuick/private/qsgtexture_p.h>
45 #include <QtGui/qopenglfunctions.h>
46 #include <qmath.h>
47
48 QT_BEGIN_NAMESPACE
49
50 class QSGDistanceFieldTextMaterialShader : public QSGMaterialShader
51 {
52 public:
53     QSGDistanceFieldTextMaterialShader();
54
55     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
56     virtual char const *const *attributeNames() const;
57
58 protected:
59     virtual void initialize();
60     virtual const char *vertexShader() const;
61     virtual const char *fragmentShader() const;
62
63     void updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc);
64
65     float m_fontScale;
66     float m_matrixScale;
67
68     int m_matrix_id;
69     int m_textureScale_id;
70     int m_alphaMin_id;
71     int m_alphaMax_id;
72     int m_color_id;
73 };
74
75 const char *QSGDistanceFieldTextMaterialShader::vertexShader() const {
76     return
77         "uniform highp mat4 matrix;                     \n"
78         "uniform highp vec2 textureScale;               \n"
79         "attribute highp vec4 vCoord;                   \n"
80         "attribute highp vec2 tCoord;                   \n"
81         "varying highp vec2 sampleCoord;                \n"
82         "void main() {                                  \n"
83         "     sampleCoord = tCoord * textureScale;      \n"
84         "     gl_Position = matrix * vCoord;            \n"
85         "}";
86 }
87
88 const char *QSGDistanceFieldTextMaterialShader::fragmentShader() const {
89     return
90         "varying highp vec2 sampleCoord;                                             \n"
91         "uniform sampler2D texture;                                                  \n"
92         "uniform lowp vec4 color;                                                    \n"
93         "uniform mediump float alphaMin;                                             \n"
94         "uniform mediump float alphaMax;                                             \n"
95         "void main() {                                                               \n"
96         "    gl_FragColor = color * smoothstep(alphaMin,                             \n"
97         "                                      alphaMax,                             \n"
98         "                                      texture2D(texture, sampleCoord).a);   \n"
99         "}";
100 }
101
102 char const *const *QSGDistanceFieldTextMaterialShader::attributeNames() const {
103     static char const *const attr[] = { "vCoord", "tCoord", 0 };
104     return attr;
105 }
106
107 QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader()
108     : m_fontScale(1.0)
109     , m_matrixScale(1.0)
110 {
111 }
112
113 void QSGDistanceFieldTextMaterialShader::updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc)
114 {
115     float combinedScale = m_fontScale * m_matrixScale;
116     float base = thresholdFunc(combinedScale);
117     float range = spreadFunc(combinedScale);
118
119     float alphaMin = qMax(0.0f, base - range);
120     float alphaMax = qMin(base + range, 1.0f);
121     program()->setUniformValue(m_alphaMin_id, GLfloat(alphaMin));
122     program()->setUniformValue(m_alphaMax_id, GLfloat(alphaMax));
123 }
124
125 void QSGDistanceFieldTextMaterialShader::initialize()
126 {
127     QSGMaterialShader::initialize();
128     m_matrix_id = program()->uniformLocation("matrix");
129     m_textureScale_id = program()->uniformLocation("textureScale");
130     m_color_id = program()->uniformLocation("color");
131     m_alphaMin_id = program()->uniformLocation("alphaMin");
132     m_alphaMax_id = program()->uniformLocation("alphaMax");
133 }
134
135 void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
136 {
137     Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
138     QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
139     QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
140
141     bool updated = material->updateTextureSize();
142
143     if (oldMaterial == 0
144            || material->color() != oldMaterial->color()
145            || state.isOpacityDirty()) {
146         QVector4D color(material->color().redF(), material->color().greenF(),
147                         material->color().blueF(), material->color().alphaF());
148         color *= state.opacity();
149         program()->setUniformValue(m_color_id, color);
150     }
151
152     bool updateRange = false;
153     if (oldMaterial == 0
154             || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()) {
155         m_fontScale = material->glyphCache()->fontScale();
156         updateRange = true;
157     }
158     if (state.isMatrixDirty()) {
159         program()->setUniformValue(m_matrix_id, state.combinedMatrix());
160         m_matrixScale = qSqrt(qAbs(state.modelViewMatrix().determinant()));
161         updateRange = true;
162     }
163     if (updateRange) {
164         updateAlphaRange(material->glyphCache()->manager()->thresholdFunc(),
165                          material->glyphCache()->manager()->antialiasingSpreadFunc());
166     }
167
168     Q_ASSERT(material->glyphCache());
169
170     if (updated
171             || oldMaterial == 0
172             || oldMaterial->texture()->textureId != material->texture()->textureId) {
173         program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->textureSize().width(),
174                                                                 1.0 / material->textureSize().height()));
175         glBindTexture(GL_TEXTURE_2D, material->texture()->textureId);
176
177         if (updated) {
178             // Set the mag/min filters to be linear. We only need to do this when the texture
179             // has been recreated.
180             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
181             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
182             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
183             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
184         }
185     }
186 }
187
188 QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial()
189     : m_glyph_cache(0)
190     , m_texture(0)
191 {
192    setFlag(Blending | RequiresDeterminant, true);
193 }
194
195 QSGDistanceFieldTextMaterial::~QSGDistanceFieldTextMaterial()
196 {
197 }
198
199 QSGMaterialType *QSGDistanceFieldTextMaterial::type() const
200 {
201     static QSGMaterialType type;
202     return &type;
203 }
204
205 QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const
206 {
207     return new QSGDistanceFieldTextMaterialShader;
208 }
209
210 bool QSGDistanceFieldTextMaterial::updateTextureSize()
211 {
212     if (!m_texture)
213         m_texture = m_glyph_cache->glyphTexture(-1); // invalid texture
214
215     if (m_texture->size != m_size) {
216         m_size = m_texture->size;
217         return true;
218     } else {
219         return false;
220     }
221 }
222
223 int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const
224 {
225     Q_ASSERT(o && type() == o->type());
226     const QSGDistanceFieldTextMaterial *other = static_cast<const QSGDistanceFieldTextMaterial *>(o);
227     if (m_glyph_cache != other->m_glyph_cache)
228         return m_glyph_cache - other->m_glyph_cache;
229     if (m_glyph_cache->fontScale() != other->m_glyph_cache->fontScale()) {
230         qreal s1 = m_glyph_cache->fontScale();
231         qreal s2 = other->m_glyph_cache->fontScale();
232         return int(s2 < s1) - int(s1 < s2);
233     }
234     QRgb c1 = m_color.rgba();
235     QRgb c2 = other->m_color.rgba();
236     return int(c2 < c1) - int(c1 < c2);
237 }
238
239
240 class DistanceFieldStyledTextMaterialShader : public QSGDistanceFieldTextMaterialShader
241 {
242 public:
243     DistanceFieldStyledTextMaterialShader();
244
245     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
246
247 protected:
248     virtual void initialize();
249     virtual const char *fragmentShader() const = 0;
250
251     int m_styleColor_id;
252 };
253
254 DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader()
255     : QSGDistanceFieldTextMaterialShader()
256 {
257 }
258
259 void DistanceFieldStyledTextMaterialShader::initialize()
260 {
261     QSGDistanceFieldTextMaterialShader::initialize();
262     m_styleColor_id = program()->uniformLocation("styleColor");
263 }
264
265 void DistanceFieldStyledTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
266 {
267     QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect);
268
269     QSGDistanceFieldStyledTextMaterial *material = static_cast<QSGDistanceFieldStyledTextMaterial *>(newEffect);
270     QSGDistanceFieldStyledTextMaterial *oldMaterial = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldEffect);
271
272     if (oldMaterial == 0
273            || material->styleColor() != oldMaterial->styleColor()
274            || (state.isOpacityDirty())) {
275         QVector4D color(material->styleColor().redF(), material->styleColor().greenF(),
276                         material->styleColor().blueF(), material->styleColor().alphaF());
277         color *= state.opacity();
278         program()->setUniformValue(m_styleColor_id, color);
279     }
280 }
281
282 QSGDistanceFieldStyledTextMaterial::QSGDistanceFieldStyledTextMaterial()
283     : QSGDistanceFieldTextMaterial()
284 {
285 }
286
287 QSGDistanceFieldStyledTextMaterial::~QSGDistanceFieldStyledTextMaterial()
288 {
289 }
290
291 int QSGDistanceFieldStyledTextMaterial::compare(const QSGMaterial *o) const
292 {
293     Q_ASSERT(o && type() == o->type());
294     const QSGDistanceFieldStyledTextMaterial *other = static_cast<const QSGDistanceFieldStyledTextMaterial *>(o);
295     if (m_styleColor != other->m_styleColor) {
296         QRgb c1 = m_styleColor.rgba();
297         QRgb c2 = other->m_styleColor.rgba();
298         return int(c2 < c1) - int(c1 < c2);
299     }
300     return QSGDistanceFieldTextMaterial::compare(o);
301 }
302
303
304 class DistanceFieldOutlineTextMaterialShader : public DistanceFieldStyledTextMaterialShader
305 {
306 public:
307     DistanceFieldOutlineTextMaterialShader();
308
309     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
310
311 protected:
312     virtual void initialize();
313     virtual const char *fragmentShader() const;
314
315     void updateOutlineAlphaRange(int dfRadius);
316
317     int m_outlineAlphaMax0_id;
318     int m_outlineAlphaMax1_id;
319 };
320
321 const char *DistanceFieldOutlineTextMaterialShader::fragmentShader() const {
322     return
323             "varying highp vec2 sampleCoord;                                                      \n"
324             "uniform sampler2D texture;                                                           \n"
325             "uniform lowp vec4 color;                                                             \n"
326             "uniform lowp vec4 styleColor;                                                        \n"
327             "uniform mediump float alphaMin;                                                      \n"
328             "uniform mediump float alphaMax;                                                      \n"
329             "uniform mediump float outlineAlphaMax0;                                              \n"
330             "uniform mediump float outlineAlphaMax1;                                              \n"
331             "void main() {                                                                        \n"
332             "    mediump float d = texture2D(texture, sampleCoord).a;                             \n"
333             "    gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d))         \n"
334             "                       * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d);          \n"
335             "}";
336 }
337
338 DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader()
339     : DistanceFieldStyledTextMaterialShader()
340 {
341 }
342
343 void DistanceFieldOutlineTextMaterialShader::initialize()
344 {
345     DistanceFieldStyledTextMaterialShader::initialize();
346     m_outlineAlphaMax0_id = program()->uniformLocation("outlineAlphaMax0");
347     m_outlineAlphaMax1_id = program()->uniformLocation("outlineAlphaMax1");
348 }
349
350 void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(int dfRadius)
351 {
352     qreal outlineLimit = qMax(qreal(0.2), qreal(0.5 - 0.5 / dfRadius / m_fontScale));
353
354     qreal combinedScale = m_fontScale * m_matrixScale;
355     qreal alphaMin = qMax(0.0, 0.5 - 0.07 / combinedScale);
356     qreal styleAlphaMin0 = qMax(0.0, outlineLimit - 0.07 / combinedScale);
357     qreal styleAlphaMin1 = qMin(qreal(outlineLimit + 0.07 / combinedScale), alphaMin);
358     program()->setUniformValue(m_outlineAlphaMax0_id, GLfloat(styleAlphaMin0));
359     program()->setUniformValue(m_outlineAlphaMax1_id, GLfloat(styleAlphaMin1));
360 }
361
362 void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
363 {
364     DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect);
365
366     QSGDistanceFieldOutlineTextMaterial *material = static_cast<QSGDistanceFieldOutlineTextMaterial *>(newEffect);
367     QSGDistanceFieldOutlineTextMaterial *oldMaterial = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldEffect);
368
369     if (oldMaterial == 0
370             || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()
371             || state.isMatrixDirty())
372         updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius());
373 }
374
375
376 QSGDistanceFieldOutlineTextMaterial::QSGDistanceFieldOutlineTextMaterial()
377     : QSGDistanceFieldStyledTextMaterial()
378 {
379 }
380
381 QSGDistanceFieldOutlineTextMaterial::~QSGDistanceFieldOutlineTextMaterial()
382 {
383 }
384
385 QSGMaterialType *QSGDistanceFieldOutlineTextMaterial::type() const
386 {
387     static QSGMaterialType type;
388     return &type;
389 }
390
391 QSGMaterialShader *QSGDistanceFieldOutlineTextMaterial::createShader() const
392 {
393     return new DistanceFieldOutlineTextMaterialShader;
394 }
395
396
397 class DistanceFieldShiftedStyleTextMaterialShader : public DistanceFieldStyledTextMaterialShader
398 {
399 public:
400     DistanceFieldShiftedStyleTextMaterialShader();
401
402     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
403
404 protected:
405     virtual void initialize();
406     virtual const char *vertexShader() const;
407     virtual const char *fragmentShader() const;
408
409     void updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF& shift);
410
411     int m_shift_id;
412 };
413
414 DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader()
415     : DistanceFieldStyledTextMaterialShader()
416 {
417 }
418
419 void DistanceFieldShiftedStyleTextMaterialShader::initialize()
420 {
421     DistanceFieldStyledTextMaterialShader::initialize();
422     m_shift_id = program()->uniformLocation("shift");
423 }
424
425 void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
426 {
427     DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect);
428
429     QSGDistanceFieldShiftedStyleTextMaterial *material = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newEffect);
430     QSGDistanceFieldShiftedStyleTextMaterial *oldMaterial = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldEffect);
431
432     if (oldMaterial == 0
433             || oldMaterial->glyphCache()->fontScale() != material->glyphCache()->fontScale()
434             || oldMaterial->shift() != material->shift()
435             || oldMaterial->textureSize() != material->textureSize()) {
436         updateShift(material->glyphCache(), material->shift());
437     }
438 }
439
440 void DistanceFieldShiftedStyleTextMaterialShader::updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF &shift)
441 {
442     QPointF texel(1.0 / cache->fontScale() * shift.x(),
443                   1.0 / cache->fontScale() * shift.y());
444     program()->setUniformValue(m_shift_id, texel);
445 }
446
447 const char *DistanceFieldShiftedStyleTextMaterialShader::vertexShader() const
448 {
449     return
450             "uniform highp mat4 matrix;                                 \n"
451             "uniform highp vec2 textureScale;                           \n"
452             "attribute highp vec4 vCoord;                               \n"
453             "attribute highp vec2 tCoord;                               \n"
454             "uniform highp vec2 shift;                                  \n"
455             "varying highp vec2 sampleCoord;                            \n"
456             "varying highp vec2 shiftedSampleCoord;                     \n"
457             "void main() {                                              \n"
458             "     sampleCoord = tCoord * textureScale;                  \n"
459             "     shiftedSampleCoord = (tCoord - shift) * textureScale; \n"
460             "     gl_Position = matrix * vCoord;                        \n"
461             "}";
462 }
463
464 const char *DistanceFieldShiftedStyleTextMaterialShader::fragmentShader() const {
465     return
466             "varying highp vec2 sampleCoord;                                                       \n"
467             "varying highp vec2 shiftedSampleCoord;                                                \n"
468             "uniform sampler2D texture;                                                            \n"
469             "uniform lowp vec4 color;                                                              \n"
470             "uniform lowp vec4 styleColor;                                                         \n"
471             "uniform mediump float alphaMin;                                                       \n"
472             "uniform mediump float alphaMax;                                                       \n"
473             "void main() {                                                                         \n"
474             "    highp float a = smoothstep(alphaMin, alphaMax, texture2D(texture, sampleCoord).a);\n"
475             "    highp vec4 shifted = styleColor * smoothstep(alphaMin,                            \n"
476             "                                                 alphaMax,                            \n"
477             "                                                 texture2D(texture, shiftedSampleCoord).a); \n"
478             "    gl_FragColor = mix(shifted, color, a);                                            \n"
479             "}";
480 }
481
482 QSGDistanceFieldShiftedStyleTextMaterial::QSGDistanceFieldShiftedStyleTextMaterial()
483     : QSGDistanceFieldStyledTextMaterial()
484 {
485 }
486
487 QSGDistanceFieldShiftedStyleTextMaterial::~QSGDistanceFieldShiftedStyleTextMaterial()
488 {
489 }
490
491 QSGMaterialType *QSGDistanceFieldShiftedStyleTextMaterial::type() const
492 {
493     static QSGMaterialType type;
494     return &type;
495 }
496
497 QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader() const
498 {
499     return new DistanceFieldShiftedStyleTextMaterialShader;
500 }
501
502
503 class QSGHiQSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTextMaterialShader
504 {
505 public:
506     virtual void initialize();
507     virtual void activate();
508     virtual void deactivate();
509     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
510
511 protected:
512     virtual const char *vertexShader() const;
513     virtual const char *fragmentShader() const;
514
515 private:
516     int m_fontScale_id;
517     int m_vecDelta_id;
518 };
519
520 const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
521     return
522         "uniform highp mat4 matrix;                                             \n"
523         "uniform highp vec2 textureScale;                                       \n"
524         "uniform highp float fontScale;                                         \n"
525         "uniform highp vec4 vecDelta;                                           \n"
526         "attribute highp vec4 vCoord;                                           \n"
527         "attribute highp vec2 tCoord;                                           \n"
528         "varying highp vec2 sampleCoord;                                        \n"
529         "varying highp vec3 sampleFarLeft;                                      \n"
530         "varying highp vec3 sampleNearLeft;                                     \n"
531         "varying highp vec3 sampleNearRight;                                    \n"
532         "varying highp vec3 sampleFarRight;                                     \n"
533         "void main() {                                                          \n"
534         "     sampleCoord = tCoord * textureScale;                              \n"
535         "     gl_Position = matrix * vCoord;                                    \n"
536         // Calculate neighbour pixel position in item space.
537         "     highp vec3 wDelta = gl_Position.w * vecDelta.xyw;                 \n"
538         "     highp vec3 farLeft = vCoord.xyw - 0.667 * wDelta;                 \n"
539         "     highp vec3 nearLeft = vCoord.xyw - 0.333 * wDelta;                \n"
540         "     highp vec3 nearRight = vCoord.xyw + 0.333 * wDelta;               \n"
541         "     highp vec3 farRight = vCoord.xyw + 0.667 * wDelta;                \n"
542         // Calculate neighbour texture coordinate.
543         "     highp vec2 scale = textureScale / fontScale;                      \n"
544         "     highp vec2 base = sampleCoord - scale * vCoord.xy;                \n"
545         "     sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z); \n"
546         "     sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
547         "     sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
548         "     sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z); \n"
549         "}";
550 }
551
552 const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
553     return
554         "varying highp vec2 sampleCoord;                                        \n"
555         "varying highp vec3 sampleFarLeft;                                      \n"
556         "varying highp vec3 sampleNearLeft;                                     \n"
557         "varying highp vec3 sampleNearRight;                                    \n"
558         "varying highp vec3 sampleFarRight;                                     \n"
559         "uniform sampler2D texture;                                             \n"
560         "uniform lowp vec4 color;                                               \n"
561         "uniform mediump float alphaMin;                                        \n"
562         "uniform mediump float alphaMax;                                        \n"
563         "void main() {                                                          \n"
564         "    highp vec4 n;                                                      \n"
565         "    n.x = texture2DProj(texture, sampleFarLeft).a;                     \n"
566         "    n.y = texture2DProj(texture, sampleNearLeft).a;                    \n"
567         "    highp float c = texture2D(texture, sampleCoord).a;                 \n"
568         "    n.z = texture2DProj(texture, sampleNearRight).a;                   \n"
569         "    n.w = texture2DProj(texture, sampleFarRight).a;                    \n"
570 #if 0
571         // Blurrier, faster.
572         "    n = smoothstep(alphaMin, alphaMax, n);                             \n"
573         "    c = smoothstep(alphaMin, alphaMax, c);                             \n"
574 #else
575         // Sharper, slower.
576         "    highp vec2 d = min(abs(n.yw - n.xz) * 2., 0.67);                   \n"
577         "    highp vec2 lo = mix(vec2(alphaMin), vec2(0.5), d);                 \n"
578         "    highp vec2 hi = mix(vec2(alphaMax), vec2(0.5), d);                 \n"
579         "    n = smoothstep(lo.xxyy, hi.xxyy, n);                               \n"
580         "    c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c);                  \n"
581 #endif
582         "    gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w;     \n"
583         "}";
584 }
585
586 //const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
587 //    return
588 //        "#extension GL_OES_standard_derivatives: enable                         \n"
589 //        "varying highp vec2 sampleCoord;                                        \n"
590 //        "uniform sampler2D texture;                                             \n"
591 //        "uniform lowp vec4 color;                                               \n"
592 //        "uniform highp float alphaMin;                                          \n"
593 //        "uniform highp float alphaMax;                                          \n"
594 //        "void main() {                                                          \n"
595 //        "    highp vec2 delta = dFdx(sampleCoord);                              \n"
596 //        "    highp vec4 n;                                                      \n"
597 //        "    n.x = texture2D(texture, sampleCoord - 0.667 * delta).a;           \n"
598 //        "    n.y = texture2D(texture, sampleCoord - 0.333 * delta).a;           \n"
599 //        "    highp float c = texture2D(texture, sampleCoord).a;                 \n"
600 //        "    n.z = texture2D(texture, sampleCoord + 0.333 * delta).a;           \n"
601 //        "    n.w = texture2D(texture, sampleCoord + 0.667 * delta).a;           \n"
602 //        "    n = smoothstep(alphaMin, alphaMax, n);                             \n"
603 //        "    c = smoothstep(alphaMin, alphaMax, c);                             \n"
604 //        "    gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w;     \n"
605 //        "}";
606 //}
607
608 void QSGHiQSubPixelDistanceFieldTextMaterialShader::initialize()
609 {
610     QSGDistanceFieldTextMaterialShader::initialize();
611     m_fontScale_id = program()->uniformLocation("fontScale");
612     m_vecDelta_id = program()->uniformLocation("vecDelta");
613 }
614
615 void QSGHiQSubPixelDistanceFieldTextMaterialShader::activate()
616 {
617     QSGDistanceFieldTextMaterialShader::activate();
618     glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
619 }
620
621 void QSGHiQSubPixelDistanceFieldTextMaterialShader::deactivate()
622 {
623     QSGDistanceFieldTextMaterialShader::deactivate();
624     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
625 }
626
627 void QSGHiQSubPixelDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
628 {
629     Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
630     QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
631     QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
632
633     if (oldMaterial == 0 || material->color() != oldMaterial->color()) {
634         QColor c = material->color();
635         state.context()->functions()->glBlendColor(c.redF(), c.greenF(), c.blueF(), 1.0f);
636     }
637
638     if (oldMaterial == 0 || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale())
639         program()->setUniformValue(m_fontScale_id, GLfloat(material->glyphCache()->fontScale()));
640
641     if (oldMaterial == 0 || state.isMatrixDirty()) {
642         int viewportWidth = state.viewportRect().width();
643         QMatrix4x4 mat = state.combinedMatrix().inverted();
644         program()->setUniformValue(m_vecDelta_id, mat.column(0) * (qreal(2) / viewportWidth));
645     }
646
647     QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect);
648 }
649
650 QSGMaterialType *QSGHiQSubPixelDistanceFieldTextMaterial::type() const
651 {
652     static QSGMaterialType type;
653     return &type;
654 }
655
656 QSGMaterialShader *QSGHiQSubPixelDistanceFieldTextMaterial::createShader() const
657 {
658     return new QSGHiQSubPixelDistanceFieldTextMaterialShader;
659 }
660
661
662 class QSGLoQSubPixelDistanceFieldTextMaterialShader : public QSGHiQSubPixelDistanceFieldTextMaterialShader
663 {
664 protected:
665     virtual const char *vertexShader() const;
666     virtual const char *fragmentShader() const;
667 };
668
669 const char *QSGLoQSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
670     return
671         "uniform highp mat4 matrix;                                             \n"
672         "uniform highp vec2 textureScale;                                       \n"
673         "uniform highp float fontScale;                                         \n"
674         "uniform highp vec4 vecDelta;                                           \n"
675         "attribute highp vec4 vCoord;                                           \n"
676         "attribute highp vec2 tCoord;                                           \n"
677         "varying highp vec3 sampleNearLeft;                                     \n"
678         "varying highp vec3 sampleNearRight;                                    \n"
679         "void main() {                                                          \n"
680         "     highp vec2 sampleCoord = tCoord * textureScale;                   \n"
681         "     gl_Position = matrix * vCoord;                                    \n"
682         // Calculate neighbour pixel position in item space.
683         "     highp vec3 wDelta = gl_Position.w * vecDelta.xyw;                 \n"
684         "     highp vec3 nearLeft = vCoord.xyw - 0.25 * wDelta;                 \n"
685         "     highp vec3 nearRight = vCoord.xyw + 0.25 * wDelta;                \n"
686         // Calculate neighbour texture coordinate.
687         "     highp vec2 scale = textureScale / fontScale;                      \n"
688         "     highp vec2 base = sampleCoord - scale * vCoord.xy;                \n"
689         "     sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
690         "     sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
691         "}";
692 }
693
694 const char *QSGLoQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
695     return
696         "varying highp vec3 sampleNearLeft;                                     \n"
697         "varying highp vec3 sampleNearRight;                                    \n"
698         "uniform sampler2D texture;                                             \n"
699         "uniform lowp vec4 color;                                               \n"
700         "uniform mediump float alphaMin;                                        \n"
701         "uniform mediump float alphaMax;                                        \n"
702         "void main() {                                                          \n"
703         "    highp vec2 n;                                                      \n"
704         "    n.x = texture2DProj(texture, sampleNearLeft).a;                    \n"
705         "    n.y = texture2DProj(texture, sampleNearRight).a;                   \n"
706         "    n = smoothstep(alphaMin, alphaMax, n);                             \n"
707         "    highp float c = 0.5 * (n.x + n.y);                                 \n"
708         "    gl_FragColor = vec4(n.x, c, n.y, c) * color.w;                     \n"
709         "}";
710 }
711
712 QSGMaterialType *QSGLoQSubPixelDistanceFieldTextMaterial::type() const
713 {
714     static QSGMaterialType type;
715     return &type;
716 }
717
718 QSGMaterialShader *QSGLoQSubPixelDistanceFieldTextMaterial::createShader() const
719 {
720     return new QSGLoQSubPixelDistanceFieldTextMaterialShader;
721 }
722
723 QT_END_NAMESPACE