69de693f094c15083958a306826853e7c775cfd0
[profile/ivi/qtdeclarative.git] / src / imports / particles / deformableparticle.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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <private/qsgcontext_p.h>
43 #include <private/qsgadaptationlayer_p.h>
44 #include <qsgnode.h>
45 #include <qsgtexturematerial.h>
46 #include <qsgtexture.h>
47 #include <QFile>
48 #include "deformableparticle.h"
49 #include <QGLFunctions>
50 #include <qsgengine.h>
51
52 QT_BEGIN_NAMESPACE
53
54 const float CONV = 0.017453292519943295;
55 class DeformableParticleMaterial : public QSGMaterial
56 {
57 public:
58     DeformableParticleMaterial()
59         : timestamp(0)
60     {
61         setFlag(Blending, true);
62     }
63
64     ~DeformableParticleMaterial()
65     {
66         delete texture;
67     }
68
69     virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
70     virtual QSGMaterialShader *createShader() const;
71     virtual int compare(const QSGMaterial *other) const
72     {
73         return this - static_cast<const DeformableParticleMaterial *>(other);
74     }
75
76     QSGTexture *texture;
77
78     qreal timestamp;
79 };
80
81
82 class DeformableParticleMaterialData : public QSGMaterialShader
83 {
84 public:
85     DeformableParticleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
86     {
87         QFile vf(vertexFile ? vertexFile : ":resources/deformablevertex.shader");
88         vf.open(QFile::ReadOnly);
89         m_vertex_code = vf.readAll();
90
91         QFile ff(fragmentFile ? fragmentFile : ":resources/deformablefragment.shader");
92         ff.open(QFile::ReadOnly);
93         m_fragment_code = ff.readAll();
94
95         Q_ASSERT(!m_vertex_code.isNull());
96         Q_ASSERT(!m_fragment_code.isNull());
97     }
98
99     void deactivate() {
100         QSGMaterialShader::deactivate();
101
102         for (int i=0; i<8; ++i) {
103             m_program.setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
104         }
105     }
106
107     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
108     {
109         DeformableParticleMaterial *m = static_cast<DeformableParticleMaterial *>(newEffect);
110         state.context()->functions()->glActiveTexture(GL_TEXTURE0);
111         m->texture->bind();
112
113         m_program.setUniformValue(m_opacity_id, state.opacity());
114         m_program.setUniformValue(m_timestamp_id, (float) m->timestamp);
115
116         if (state.isMatrixDirty())
117             m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
118     }
119
120     virtual void initialize() {
121         m_matrix_id = m_program.uniformLocation("matrix");
122         m_opacity_id = m_program.uniformLocation("opacity");
123         m_timestamp_id = m_program.uniformLocation("timestamp");
124     }
125
126     virtual const char *vertexShader() const { return m_vertex_code.constData(); }
127     virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
128
129     virtual char const *const *attributeNames() const {
130         static const char *attr[] = {
131             "vPos",
132             "vTex",
133             "vData",
134             "vVec",
135             "vDeformVec",
136             "vRotation",
137             0
138         };
139         return attr;
140     }
141
142     virtual bool isColorTable() const { return false; }
143
144     int m_matrix_id;
145     int m_opacity_id;
146     int m_timestamp_id;
147
148     QByteArray m_vertex_code;
149     QByteArray m_fragment_code;
150
151     static float chunkOfBytes[1024];
152 };
153 float DeformableParticleMaterialData::chunkOfBytes[1024];
154
155
156 QSGMaterialShader *DeformableParticleMaterial::createShader() const
157 {
158     return new DeformableParticleMaterialData;
159 }
160
161 struct DeformableParticleVertex {
162     float x;
163     float y;
164     float tx;
165     float ty;
166     float t;
167     float lifeSpan;
168     float size;
169     float endSize;
170     float sx;
171     float sy;
172     float ax;
173     float ay;
174     float xx;
175     float xy;
176     float yx;
177     float yy;
178     float rotation;
179     float rotationSpeed;
180     float autoRotate;//Assume that GPUs prefer floats to bools
181 };
182
183 struct DeformableParticleVertices {
184     DeformableParticleVertex v1;
185     DeformableParticleVertex v2;
186     DeformableParticleVertex v3;
187     DeformableParticleVertex v4;
188 };
189
190
191 DeformableParticle::DeformableParticle(QSGItem* parent)
192     : ParticleType(parent)
193     , m_do_reset(false)
194     , m_rotation(0)
195     , m_autoRotation(false)
196     , m_xVector(0)
197     , m_yVector(0)
198     , m_rotationVariation(0)
199     , m_rotationSpeed(0)
200     , m_rotationSpeedVariation(0)
201 {
202     setFlag(ItemHasContents);
203 }
204
205 void DeformableParticle::setImage(const QUrl &image)
206 {
207     if (image == m_image)
208         return;
209     m_image = image;
210     emit imageChanged();
211     reset();
212 }
213
214 void DeformableParticle::setCount(int c)
215 {
216     ParticleType::setCount(c);
217     m_pleaseReset = true;
218 }
219
220 void DeformableParticle::reset()
221 {
222     ParticleType::reset();
223      m_pleaseReset = true;
224 }
225
226 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
227     { 0, 2, GL_FLOAT },             // Position
228     { 1, 2, GL_FLOAT },             // TexCoord
229     { 2, 4, GL_FLOAT },             // Data
230     { 3, 4, GL_FLOAT },             // Vectors
231     { 4, 4, GL_FLOAT },             // DeformationVectors
232     { 5, 3, GL_FLOAT }              // Rotation
233 };
234
235 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
236 {
237     6, // Attribute Count
238     (2 + 2 + 4 + 4 + 4 + 3) * sizeof(float),
239     DeformableParticle_Attributes
240 };
241
242 QSGGeometryNode* DeformableParticle::buildParticleNode()
243 {
244     if (m_count * 4 > 0xffff) {
245         printf("DeformableParticle: Too many particles... \n");
246         return 0;
247     }
248
249     if(m_count <= 0) {
250         printf("DeformableParticle: Too few particles... \n");
251         return 0;
252     }
253
254     QImage image(m_image.toLocalFile());
255     if (image.isNull()) {
256         printf("DeformableParticle: loading image failed... '%s'\n", qPrintable(m_image.toLocalFile()));
257         return 0;
258     }
259
260     int vCount = m_count * 4;
261     int iCount = m_count * 6;
262
263     QSGGeometry *g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
264     g->setDrawingMode(GL_TRIANGLES);
265
266     DeformableParticleVertex *vertices = (DeformableParticleVertex *) g->vertexData();
267     for (int p=0; p<m_count; ++p) {
268
269         for (int i=0; i<4; ++i) {
270             vertices[i].x = 0;
271             vertices[i].y = 0;
272             vertices[i].t = -1;
273             vertices[i].lifeSpan = 0;
274             vertices[i].size = 0;
275             vertices[i].endSize = 0;
276             vertices[i].sx = 0;
277             vertices[i].sy = 0;
278             vertices[i].ax = 0;
279             vertices[i].ay = 0;
280             vertices[i].xx = 1;
281             vertices[i].xy = 0;
282             vertices[i].yx = 0;
283             vertices[i].yy = 1;
284             vertices[i].rotation = 0;
285             vertices[i].rotationSpeed = 0;
286             vertices[i].autoRotate = 0;
287         }
288
289         vertices[0].tx = 0;
290         vertices[0].ty = 0;
291
292         vertices[1].tx = 1;
293         vertices[1].ty = 0;
294
295         vertices[2].tx = 0;
296         vertices[2].ty = 1;
297
298         vertices[3].tx = 1;
299         vertices[3].ty = 1;
300
301         vertices += 4;
302     }
303
304     quint16 *indices = g->indexDataAsUShort();
305     for (int i=0; i<m_count; ++i) {
306         int o = i * 4;
307         indices[0] = o;
308         indices[1] = o + 1;
309         indices[2] = o + 2;
310         indices[3] = o + 1;
311         indices[4] = o + 3;
312         indices[5] = o + 2;
313         indices += 6;
314     }
315
316     if (m_material) {
317         delete m_material;
318         m_material = 0;
319     }
320
321     if (!m_material)
322         m_material = new DeformableParticleMaterial();
323
324
325     m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
326     m_material->texture->setFiltering(QSGTexture::Linear);
327
328     m_node = new QSGGeometryNode();
329     m_node->setGeometry(g);
330     m_node->setMaterial(m_material);
331
332     m_last_particle = 0;
333
334     return m_node;
335 }
336
337 QSGNode *DeformableParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
338 {
339     if(m_pleaseReset){
340         if(m_node)
341             delete m_node;
342         if(m_material)
343             delete m_material;
344
345         m_node = 0;
346         m_material = 0;
347         m_pleaseReset = false;
348     }
349
350     if(m_system && m_system->isRunning())
351         prepareNextFrame();
352     if (m_node){
353         update();
354         m_node->markDirty(QSGNode::DirtyMaterial);
355     }
356
357     return m_node;
358 }
359
360 void DeformableParticle::prepareNextFrame()
361 {
362     if (m_node == 0){    //TODO: Staggered loading (as emitted)
363         m_node = buildParticleNode();
364         if(m_node == 0)
365             return;
366     }
367     uint timeStamp = m_system->systemSync(this);
368
369     qreal time = timeStamp / 1000.;
370     m_material->timestamp = time;
371
372 }
373
374
375 void DeformableParticle::vertexCopy(DeformableParticleVertex &b,const ParticleVertex& a)
376 {
377     b.x = a.x - m_systemOffset.x();
378     b.y = a.y - m_systemOffset.y();
379     b.t = a.t;
380     b.lifeSpan = a.lifeSpan;
381     b.size = a.size;
382     b.endSize = a.endSize;
383     b.sx = a.sx;
384     b.sy = a.sy;
385     b.ax = a.ax;
386     b.ay = a.ay;
387 }
388
389 void DeformableParticle::reload(ParticleData *d)
390 {
391     if (m_node == 0)
392         return;
393
394     DeformableParticleVertices *particles = (DeformableParticleVertices *) m_node->geometry()->vertexData();
395
396     int pos = particleTypeIndex(d);
397
398     DeformableParticleVertices &p = particles[pos];
399
400     //Perhaps we could be more efficient?
401     vertexCopy(p.v1, d->pv);
402     vertexCopy(p.v2, d->pv);
403     vertexCopy(p.v3, d->pv);
404     vertexCopy(p.v4, d->pv);
405     //TODO: Allow for change of deformation data?
406 }
407
408 void DeformableParticle::load(ParticleData *d)
409 {
410     if (m_node == 0)
411         return;
412
413     //Deformation Initialization
414     DeformableParticleVertices *particles = (DeformableParticleVertices *) m_node->geometry()->vertexData();
415     DeformableParticleVertices &p = particles[particleTypeIndex(d)];
416     if(m_xVector){
417         const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
418         p.v1.xx = p.v2.xx = p.v3.xx = p.v4.xx = ret.x();
419         p.v1.xy = p.v2.xy = p.v3.xy = p.v4.xy = ret.y();
420     }
421     if(m_yVector){
422         const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
423         p.v1.yx = p.v2.yx = p.v3.yx = p.v4.yx = ret.x();
424         p.v1.yy = p.v2.yy = p.v3.yy = p.v4.yy = ret.y();
425     }
426     p.v1.rotation = p.v2.rotation = p.v3.rotation = p.v4.rotation =
427             (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
428     p.v1.rotationSpeed = p.v2.rotationSpeed = p.v3.rotationSpeed = p.v4.rotationSpeed =
429             (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
430     p.v1.autoRotate = p.v2.autoRotate = p.v3.autoRotate = p.v4.autoRotate = m_autoRotation?1.0:0.0;
431
432     vertexCopy(p.v1, d->pv);
433     vertexCopy(p.v2, d->pv);
434     vertexCopy(p.v3, d->pv);
435     vertexCopy(p.v4, d->pv);
436 }
437
438 QT_END_NAMESPACE