1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Declarative module of the Qt Toolkit.
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
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include <private/qsgcontext_p.h>
43 #include <private/qsgadaptationlayer_p.h>
45 #include <qsgtexturematerial.h>
46 #include <qsgtexture.h>
48 #include "deformableparticle.h"
49 #include <QGLFunctions>
50 #include <qsgengine.h>
54 const float CONV = 0.017453292519943295;
55 class DeformableParticleMaterial : public QSGMaterial
58 DeformableParticleMaterial()
61 setFlag(Blending, true);
64 ~DeformableParticleMaterial()
69 virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
70 virtual QSGMaterialShader *createShader() const;
71 virtual int compare(const QSGMaterial *other) const
73 return this - static_cast<const DeformableParticleMaterial *>(other);
82 class DeformableParticleMaterialData : public QSGMaterialShader
85 DeformableParticleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
87 QFile vf(vertexFile ? vertexFile : ":resources/deformablevertex.shader");
88 vf.open(QFile::ReadOnly);
89 m_vertex_code = vf.readAll();
91 QFile ff(fragmentFile ? fragmentFile : ":resources/deformablefragment.shader");
92 ff.open(QFile::ReadOnly);
93 m_fragment_code = ff.readAll();
95 Q_ASSERT(!m_vertex_code.isNull());
96 Q_ASSERT(!m_fragment_code.isNull());
100 QSGMaterialShader::deactivate();
102 for (int i=0; i<8; ++i) {
103 m_program.setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
107 virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
109 DeformableParticleMaterial *m = static_cast<DeformableParticleMaterial *>(newEffect);
110 state.context()->functions()->glActiveTexture(GL_TEXTURE0);
113 m_program.setUniformValue(m_opacity_id, state.opacity());
114 m_program.setUniformValue(m_timestamp_id, (float) m->timestamp);
116 if (state.isMatrixDirty())
117 m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
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");
126 virtual const char *vertexShader() const { return m_vertex_code.constData(); }
127 virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
129 virtual char const *const *attributeNames() const {
130 static const char *attr[] = {
142 virtual bool isColorTable() const { return false; }
148 QByteArray m_vertex_code;
149 QByteArray m_fragment_code;
151 static float chunkOfBytes[1024];
153 float DeformableParticleMaterialData::chunkOfBytes[1024];
156 QSGMaterialShader *DeformableParticleMaterial::createShader() const
158 return new DeformableParticleMaterialData;
161 struct DeformableParticleVertex {
180 float autoRotate;//Assume that GPUs prefer floats to bools
183 struct DeformableParticleVertices {
184 DeformableParticleVertex v1;
185 DeformableParticleVertex v2;
186 DeformableParticleVertex v3;
187 DeformableParticleVertex v4;
191 DeformableParticle::DeformableParticle(QSGItem* parent)
192 : ParticleType(parent)
195 , m_autoRotation(false)
198 , m_rotationVariation(0)
200 , m_rotationSpeedVariation(0)
202 setFlag(ItemHasContents);
205 void DeformableParticle::setImage(const QUrl &image)
207 if (image == m_image)
214 void DeformableParticle::setCount(int c)
216 ParticleType::setCount(c);
217 m_pleaseReset = true;
220 void DeformableParticle::reset()
222 ParticleType::reset();
223 m_pleaseReset = true;
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
235 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
237 6, // Attribute Count
238 (2 + 2 + 4 + 4 + 4 + 3) * sizeof(float),
239 DeformableParticle_Attributes
242 QSGGeometryNode* DeformableParticle::buildParticleNode()
244 if (m_count * 4 > 0xffff) {
245 printf("DeformableParticle: Too many particles... \n");
250 printf("DeformableParticle: Too few particles... \n");
254 QImage image(m_image.toLocalFile());
255 if (image.isNull()) {
256 printf("DeformableParticle: loading image failed... '%s'\n", qPrintable(m_image.toLocalFile()));
260 int vCount = m_count * 4;
261 int iCount = m_count * 6;
263 QSGGeometry *g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
264 g->setDrawingMode(GL_TRIANGLES);
266 DeformableParticleVertex *vertices = (DeformableParticleVertex *) g->vertexData();
267 for (int p=0; p<m_count; ++p) {
269 for (int i=0; i<4; ++i) {
273 vertices[i].lifeSpan = 0;
274 vertices[i].size = 0;
275 vertices[i].endSize = 0;
284 vertices[i].rotation = 0;
285 vertices[i].rotationSpeed = 0;
286 vertices[i].autoRotate = 0;
304 quint16 *indices = g->indexDataAsUShort();
305 for (int i=0; i<m_count; ++i) {
322 m_material = new DeformableParticleMaterial();
325 m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
326 m_material->texture->setFiltering(QSGTexture::Linear);
328 m_node = new QSGGeometryNode();
329 m_node->setGeometry(g);
330 m_node->setMaterial(m_material);
337 QSGNode *DeformableParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
347 m_pleaseReset = false;
350 if(m_system && m_system->isRunning())
354 m_node->markDirty(QSGNode::DirtyMaterial);
360 void DeformableParticle::prepareNextFrame()
362 if (m_node == 0){ //TODO: Staggered loading (as emitted)
363 m_node = buildParticleNode();
367 uint timeStamp = m_system->systemSync(this);
369 qreal time = timeStamp / 1000.;
370 m_material->timestamp = time;
375 void DeformableParticle::vertexCopy(DeformableParticleVertex &b,const ParticleVertex& a)
377 b.x = a.x - m_systemOffset.x();
378 b.y = a.y - m_systemOffset.y();
380 b.lifeSpan = a.lifeSpan;
382 b.endSize = a.endSize;
389 void DeformableParticle::reload(ParticleData *d)
394 DeformableParticleVertices *particles = (DeformableParticleVertices *) m_node->geometry()->vertexData();
396 int pos = particleTypeIndex(d);
398 DeformableParticleVertices &p = particles[pos];
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?
408 void DeformableParticle::load(ParticleData *d)
413 //Deformation Initialization
414 DeformableParticleVertices *particles = (DeformableParticleVertices *) m_node->geometry()->vertexData();
415 DeformableParticleVertices &p = particles[particleTypeIndex(d)];
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();
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();
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;
432 vertexCopy(p.v1, d->pv);
433 vertexCopy(p.v2, d->pv);
434 vertexCopy(p.v3, d->pv);
435 vertexCopy(p.v4, d->pv);