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