Merge branch 'refactor'
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgspriteimage.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 Declarative 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 "qsgspriteimage_p.h"
43 #include "qsgsprite_p.h"
44 #include "qsgspriteengine_p.h"
45 #include <private/qsgcontext_p.h>
46 #include <private/qsgadaptationlayer_p.h>
47 #include <qsgnode.h>
48 #include <qsgengine.h>
49 #include <qsgtexturematerial.h>
50 #include <qsgtexture.h>
51 #include <QFile>
52 #include <cmath>
53 #include <qmath.h>
54 #include <QDebug>
55
56 QT_BEGIN_NAMESPACE
57
58 class QSGSpriteMaterial : public QSGMaterial
59 {
60 public:
61     QSGSpriteMaterial();
62     virtual ~QSGSpriteMaterial();
63     virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
64     virtual QSGMaterialShader *createShader() const;
65     virtual int compare(const QSGMaterial *other) const
66     {
67         return this - static_cast<const QSGSpriteMaterial *>(other);
68     }
69
70     QSGTexture *texture;
71
72     qreal timestamp;
73     qreal timelength;
74     int framecount;
75     int animcount;
76     int width;
77     int height;
78 };
79
80 QSGSpriteMaterial::QSGSpriteMaterial()
81     : timestamp(0)
82     , timelength(1)
83     , framecount(1)
84     , animcount(1)
85     , width(0)
86     , height(0)
87 {
88     setFlag(Blending, true);
89 }
90
91 QSGSpriteMaterial::~QSGSpriteMaterial()
92 {
93     delete texture;
94 }
95
96 class SpriteMaterialData : public QSGMaterialShader
97 {
98 public:
99     SpriteMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
100     {
101         QFile vf(vertexFile ? vertexFile : ":defaultshaders/spriteimagevertex.shader");
102         vf.open(QFile::ReadOnly);
103         m_vertex_code = vf.readAll();
104
105         QFile ff(fragmentFile ? fragmentFile : ":defaultshaders/spriteimagefragment.shader");
106         ff.open(QFile::ReadOnly);
107         m_fragment_code = ff.readAll();
108
109         Q_ASSERT(!m_vertex_code.isNull());
110         Q_ASSERT(!m_fragment_code.isNull());
111     }
112
113     void deactivate() {
114         QSGMaterialShader::deactivate();
115
116         for (int i=0; i<8; ++i) {
117             program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
118         }
119     }
120
121     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
122     {
123         QSGSpriteMaterial *m = static_cast<QSGSpriteMaterial *>(newEffect);
124         m->texture->bind();
125
126         program()->setUniformValue(m_opacity_id, state.opacity());
127         program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
128         program()->setUniformValue(m_framecount_id, (float) m->framecount);
129         program()->setUniformValue(m_animcount_id, (float) m->animcount);
130         program()->setUniformValue(m_width_id, (float) m->width);
131         program()->setUniformValue(m_height_id, (float) m->height);
132
133         if (state.isMatrixDirty())
134             program()->setUniformValue(m_matrix_id, state.combinedMatrix());
135     }
136
137     virtual void initialize() {
138         m_matrix_id = program()->uniformLocation("matrix");
139         m_opacity_id = program()->uniformLocation("opacity");
140         m_timestamp_id = program()->uniformLocation("timestamp");
141         m_framecount_id = program()->uniformLocation("framecount");
142         m_animcount_id = program()->uniformLocation("animcount");
143         m_width_id = program()->uniformLocation("width");
144         m_height_id = program()->uniformLocation("height");
145     }
146
147     virtual const char *vertexShader() const { return m_vertex_code.constData(); }
148     virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
149
150     virtual char const *const *attributeNames() const {
151         static const char *attr[] = {
152            "vTex",
153            "vAnimData",
154             0
155         };
156         return attr;
157     }
158
159     virtual bool isColorTable() const { return false; }
160
161     int m_matrix_id;
162     int m_opacity_id;
163     int m_timestamp_id;
164     int m_framecount_id;
165     int m_animcount_id;
166     int m_width_id;
167     int m_height_id;
168
169     QByteArray m_vertex_code;
170     QByteArray m_fragment_code;
171
172     static float chunkOfBytes[1024];
173 };
174 float SpriteMaterialData::chunkOfBytes[1024];
175
176 QSGMaterialShader *QSGSpriteMaterial::createShader() const
177 {
178     return new SpriteMaterialData;
179 }
180
181 struct SpriteVertex {
182     float tx;
183     float ty;
184     float animIdx;
185     float frameDuration;
186     float frameCount;
187     float animT;
188 };
189
190 struct SpriteVertices {
191     SpriteVertex v1;
192     SpriteVertex v2;
193     SpriteVertex v3;
194     SpriteVertex v4;
195 };
196
197 QSGSpriteImage::QSGSpriteImage(QSGItem *parent) :
198     QSGItem(parent)
199     , m_node(0)
200     , m_material(0)
201     , m_spriteEngine(0)
202     , m_pleaseReset(false)
203     , m_running(true)
204 {
205     setFlag(ItemHasContents);
206     connect(this, SIGNAL(runningChanged(bool)),
207             this, SLOT(update()));
208 }
209
210 QDeclarativeListProperty<QSGSprite> QSGSpriteImage::sprites()
211 {
212     return QDeclarativeListProperty<QSGSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
213 }
214
215 void QSGSpriteImage::createEngine()
216 {
217     //TODO: delay until component complete
218     if(m_spriteEngine)
219         delete m_spriteEngine;
220     if(m_sprites.count())
221         m_spriteEngine = new QSGSpriteEngine(m_sprites, this);
222     else
223         m_spriteEngine = 0;
224     reset();
225 }
226
227 static QSGGeometry::Attribute SpriteImage_Attributes[] = {
228     QSGGeometry::Attribute::create(0, 2, GL_FLOAT),         // tex
229     QSGGeometry::Attribute::create(1, 4, GL_FLOAT)          // animData
230 };
231
232 static QSGGeometry::AttributeSet SpriteImage_AttributeSet =
233 {
234     2, // Attribute Count
235     (4 + 2) * sizeof(float),
236     SpriteImage_Attributes
237 };
238
239 QSGGeometryNode* QSGSpriteImage::buildNode()
240 {
241     if (!m_spriteEngine) {
242         qWarning() << "SpriteImage: No sprite engine...";
243         return 0;
244     }
245
246     if (m_material) {
247         delete m_material;
248         m_material = 0;
249     }
250
251     m_material = new QSGSpriteMaterial();
252
253     QImage image = m_spriteEngine->assembledImage();
254     if(image.isNull())
255         return 0;
256     m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
257     m_material->texture->setFiltering(QSGTexture::Linear);
258     m_material->framecount = m_spriteEngine->maxFrames();
259
260     int vCount = 4;
261     int iCount = 6;
262     QSGGeometry *g = new QSGGeometry(SpriteImage_AttributeSet, vCount, iCount);
263     g->setDrawingMode(GL_TRIANGLES);
264
265     SpriteVertices *p = (SpriteVertices *) g->vertexData();
266     m_spriteEngine->start(0);
267     p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = 0;
268     p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = 0;
269     p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames();
270     p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->spriteDuration();
271
272     p->v1.tx = 0;
273     p->v1.ty = 0;
274
275     p->v2.tx = 1.0;
276     p->v2.ty = 0;
277
278     p->v3.tx = 0;
279     p->v3.ty = 1.0;
280
281     p->v4.tx = 1.0;
282     p->v4.ty = 1.0;
283
284     quint16 *indices = g->indexDataAsUShort();
285     indices[0] = 0;
286     indices[1] = 1;
287     indices[2] = 2;
288     indices[3] = 1;
289     indices[4] = 3;
290     indices[5] = 2;
291
292
293     m_timestamp.start();
294     m_node = new QSGGeometryNode();
295     m_node->setGeometry(g);
296     m_node->setMaterial(m_material);
297     return m_node;
298 }
299
300 void QSGSpriteImage::reset()
301 {
302     m_pleaseReset = true;
303 }
304
305 QSGNode *QSGSpriteImage::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
306 {
307     if(m_pleaseReset){
308         delete m_node;
309         delete m_material;
310
311         m_node = 0;
312         m_material = 0;
313         m_pleaseReset = false;
314     }
315
316     prepareNextFrame();
317
318     if(m_running){
319         update();
320         if (m_node)
321             m_node->markDirty(QSGNode::DirtyMaterial);
322     }
323
324     return m_node;
325 }
326
327 void QSGSpriteImage::prepareNextFrame()
328 {
329     if (m_node == 0)
330         m_node = buildNode();
331     if (m_node == 0) //error creating node
332         return;
333
334     uint timeInt = m_timestamp.elapsed();
335     qreal time =  timeInt / 1000.;
336     m_material->timestamp = time;
337     m_material->animcount = m_spriteEngine->spriteCount();
338     m_material->height = height();
339     m_material->width = width();
340
341     //Advance State
342     SpriteVertices *p = (SpriteVertices *) m_node->geometry()->vertexData();
343     m_spriteEngine->updateSprites(timeInt);
344     int curIdx = m_spriteEngine->spriteState();
345     if(curIdx != p->v1.animIdx){
346         p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = curIdx;
347         p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = m_spriteEngine->spriteStart()/1000.0;
348         p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames();
349         p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->spriteDuration();
350     }
351 }
352
353 QT_END_NAMESPACE