aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports/particles/ultraparticle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imports/particles/ultraparticle.cpp')
-rw-r--r--src/imports/particles/ultraparticle.cpp347
1 files changed, 286 insertions, 61 deletions
diff --git a/src/imports/particles/ultraparticle.cpp b/src/imports/particles/ultraparticle.cpp
index 6dd05aa597..d516f9952d 100644
--- a/src/imports/particles/ultraparticle.cpp
+++ b/src/imports/particles/ultraparticle.cpp
@@ -58,10 +58,11 @@ const float CONV = 0.017453292519943295;
class UltraMaterial : public QSGMaterial
{
public:
- UltraMaterial()
+ UltraMaterial(bool withSprites=false)
: timestamp(0)
, framecount(1)
, animcount(1)
+ , usesSprites(withSprites)
{
setFlag(Blending, true);
}
@@ -89,9 +90,8 @@ public:
qreal timestamp;
int framecount;
int animcount;
+ bool usesSprites;
};
-
-
class UltraMaterialData : public QSGMaterialShader
{
public:
@@ -191,17 +191,99 @@ public:
};
float UltraMaterialData::chunkOfBytes[1024];
-
QSGMaterialShader *UltraMaterial::createShader() const
{
- return new UltraMaterialData;
+ if(usesSprites)//TODO: Perhaps just swap the shaders, and don't mind the extra vector?
+ return new UltraMaterialData;
+ else
+ return new UltraMaterialData;
+}
+
+
+class SimpleMaterial : public UltraMaterial
+{
+ virtual QSGMaterialShader *createShader() const;
+};
+
+class SimpleMaterialData : public QSGMaterialShader
+{
+public:
+ SimpleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/simplevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/simplefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SimpleMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *SimpleMaterial::createShader() const {
+ return new SimpleMaterialData;
}
UltraParticle::UltraParticle(QSGItem* parent)
: ParticleType(parent)
, m_do_reset(false)
- , m_color(Qt::white)
- , m_color_variation(0.5)
+ , m_color_variation(0.0)
, m_node(0)
, m_material(0)
, m_alphaVariation(0.0)
@@ -217,6 +299,8 @@ UltraParticle::UltraParticle(QSGItem* parent)
, m_rotationSpeed(0)
, m_rotationSpeedVariation(0)
, m_spriteEngine(0)
+ , m_bloat(false)
+ , perfLevel(Unknown)
{
setFlag(ItemHasContents);
}
@@ -269,7 +353,6 @@ void UltraParticle::setColor(const QColor &color)
return;
m_color = color;
emit colorChanged();
- //m_system->pleaseReset();//XXX
}
void UltraParticle::setColorVariation(qreal var)
@@ -278,7 +361,6 @@ void UltraParticle::setColorVariation(qreal var)
return;
m_color_variation = var;
emit colorVariationChanged();
- //m_system->pleaseReset();//XXX
}
void UltraParticle::setCount(int c)
@@ -301,9 +383,23 @@ void UltraParticle::createEngine()
m_spriteEngine = new SpriteEngine(m_sprites, this);
else
m_spriteEngine = 0;
- reset();//###this is probably out of updatePaintNode and shouldn't be
+ reset();
}
+static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT } // Vectors
+};
+
+static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
+{
+ 4, // Attribute Count
+ (2 + 2 + 4 + 4 ) * sizeof(float),
+ SimpleParticle_Attributes
+};
+
static QSGGeometry::Attribute UltraParticle_Attributes[] = {
{ 0, 2, GL_FLOAT }, // Position
{ 1, 2, GL_FLOAT }, // TexCoord
@@ -322,10 +418,85 @@ static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
UltraParticle_Attributes
};
+QSGGeometryNode* UltraParticle::buildSimpleParticleNode()
+{
+ perfLevel = Simple;//TODO: Intermediate levels
+ QImage image = QImage(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+ qDebug() << "Simple Case";
+
+ QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SimpleVertex *vertices = (SimpleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = 0;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ m_material = new SimpleMaterial();
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+ m_material->framecount = 1;
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
QSGGeometryNode* UltraParticle::buildParticleNode()
{
if (m_count * 4 > 0xffff) {
- printf("UltraParticle: Too many particles... \n");
+ printf("UltraParticle: Too many particles... \n");//####Why is this here?
return 0;
}
@@ -334,6 +505,21 @@ QSGGeometryNode* UltraParticle::buildParticleNode()
return 0;
}
+ qDebug() << m_colortable_name.isEmpty() << !m_color.isValid();
+ if(!m_sprites.count() && !m_bloat
+ && m_colortable_name.isEmpty()
+ && m_sizetable_name.isEmpty()
+ && m_opacitytable_name.isEmpty()
+ && !m_rotation && !m_rotationVariation
+ && !m_rotationSpeed && !m_rotationSpeedVariation
+ && !m_alphaVariation && m_alpha == 1.0
+ && !m_redVariation && !m_blueVariation && !m_greenVariation
+ && !m_color.isValid()
+ )
+ return buildSimpleParticleNode();
+ perfLevel = Sprites;//TODO: intermediate levels
+ qDebug() << "Complex Case";
+
QImage image;
if(m_sprites.count()){
if (!m_spriteEngine) {
@@ -480,6 +666,7 @@ void UltraParticle::prepareNextFrame()
m_node = buildParticleNode();
if(m_node == 0)
return;
+ qDebug() << "Feature level: " << perfLevel;
}
qint64 timeStamp = m_system->systemSync(this);
@@ -487,7 +674,7 @@ void UltraParticle::prepareNextFrame()
m_material->timestamp = time;
//Advance State
- if(m_spriteEngine){
+ if(m_spriteEngine){//perfLevel == Sprites?
m_material->animcount = m_spriteEngine->stateCount();
UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
m_spriteEngine->updateSprites(timeStamp);
@@ -506,6 +693,37 @@ void UltraParticle::prepareNextFrame()
}
}
+template <typename VT>
+IntermediateVertices* transplant(IntermediateVertices* iv, VT &v)
+{//Deliberate typemangling cast
+ iv->v1 = (UltraVertex*)&(v.v1);
+ iv->v2 = (UltraVertex*)&(v.v2);
+ iv->v3 = (UltraVertex*)&(v.v3);
+ iv->v4 = (UltraVertex*)&(v.v4);
+ return iv;
+}
+
+IntermediateVertices* UltraParticle::fetchIntermediateVertices(int pos)
+{
+ //Note that this class ruins typesafety for you. Maybe even thread safety.
+ //TODO: Something better, possibly with templates or inheritance
+ static IntermediateVertices iv;
+ SimpleVertices *sv;
+ UltraVertices *uv;
+ switch(perfLevel){
+ case Simple:
+ sv = (SimpleVertices *) m_node->geometry()->vertexData();
+ return transplant(&iv, sv[pos]);
+ case Coloured:
+ case Deformable:
+ case Tabled:
+ case Sprites:
+ default:
+ uv = (UltraVertices *) m_node->geometry()->vertexData();
+ return transplant(&iv,uv[pos]);
+ }
+}
+
void UltraParticle::reloadColor(const Color4ub &c, ParticleData* d)
{
UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
@@ -514,6 +732,7 @@ void UltraParticle::reloadColor(const Color4ub &c, ParticleData* d)
p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
}
+/*Repalced by superclass templated function
void UltraParticle::vertexCopy(UltraVertex &b,const ParticleVertex& a)
{
b.x = a.x - m_systemOffset.x();
@@ -527,23 +746,22 @@ void UltraParticle::vertexCopy(UltraVertex &b,const ParticleVertex& a)
b.ax = a.ax;
b.ay = a.ay;
}
+*/
+
void UltraParticle::reload(ParticleData *d)
{
if (m_node == 0)
return;
- UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
-
int pos = particleTypeIndex(d);
-
- UltraVertices &p = particles[pos];
+ IntermediateVertices* p = fetchIntermediateVertices(pos);
//Perhaps we could be more efficient?
- vertexCopy(p.v1, d->pv);
- vertexCopy(p.v2, d->pv);
- vertexCopy(p.v3, d->pv);
- vertexCopy(p.v4, d->pv);
+ vertexCopy(*p->v1, d->pv);
+ vertexCopy(*p->v2, d->pv);
+ vertexCopy(*p->v3, d->pv);
+ vertexCopy(*p->v4, d->pv);
}
void UltraParticle::load(ParticleData *d)
@@ -551,53 +769,60 @@ void UltraParticle::load(ParticleData *d)
if (m_node == 0)
return;
- //Color initialization
- // Particle color
+ int pos = particleTypeIndex(d);
+ IntermediateVertices* p = fetchIntermediateVertices(pos);//Remember this removes typesafety!
Color4ub color;
qreal redVariation = m_color_variation + m_redVariation;
qreal greenVariation = m_color_variation + m_greenVariation;
qreal blueVariation = m_color_variation + m_blueVariation;
- color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
- color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
- color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
- color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
- UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
- UltraVertices &p = particles[particleTypeIndex(d)];
- p.v1.color = p.v2.color = p.v3.color = p.v4.color = color;
- //Initial Rotation
- if(m_xVector){
- const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
- p.v1.xx = p.v2.xx = p.v3.xx = p.v4.xx = ret.x();
- p.v1.xy = p.v2.xy = p.v3.xy = p.v4.xy = ret.y();
- }
- if(m_yVector){
- const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
- p.v1.yx = p.v2.yx = p.v3.yx = p.v4.yx = ret.x();
- p.v1.yy = p.v2.yy = p.v3.yy = p.v4.yy = ret.y();
- }
- p.v1.rotation = p.v2.rotation = p.v3.rotation = p.v4.rotation =
- (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
- p.v1.rotationSpeed = p.v2.rotationSpeed = p.v3.rotationSpeed = p.v4.rotationSpeed =
- (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
- p.v1.autoRotate = p.v2.autoRotate = p.v3.autoRotate = p.v4.autoRotate = m_autoRotation?1.0:0.0;
- // Initial Sprite State
- p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = p.v1.t;
- p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = 0;
- if(m_spriteEngine){
- SpriteState* state = m_spriteEngine->state(0);
- p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = state->frames();
- p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = state->duration();
- m_spriteEngine->startSprite(particleTypeIndex(d));
- }else{
- p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = 1;
- p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = 9999;
+ switch(perfLevel){//Fall-through is intended on all of them
+ case Sprites:
+ // Initial Sprite State
+ p->v1->animT = p->v2->animT = p->v3->animT = p->v4->animT = p->v1->t;
+ p->v1->animIdx = p->v2->animIdx = p->v3->animIdx = p->v4->animIdx = 0;
+ if(m_spriteEngine){
+ SpriteState* state = m_spriteEngine->state(0);
+ p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = state->frames();
+ p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = state->duration();
+ m_spriteEngine->startSprite(pos);
+ }else{
+ p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = 1;
+ p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = 9999;
+ }
+ case Tabled:
+ case Deformable:
+ //Initial Rotation
+ if(m_xVector){
+ const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
+ p->v1->xx = p->v2->xx = p->v3->xx = p->v4->xx = ret.x();
+ p->v1->xy = p->v2->xy = p->v3->xy = p->v4->xy = ret.y();
+ }
+ if(m_yVector){
+ const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
+ p->v1->yx = p->v2->yx = p->v3->yx = p->v4->yx = ret.x();
+ p->v1->yy = p->v2->yy = p->v3->yy = p->v4->yy = ret.y();
+ }
+ p->v1->rotation = p->v2->rotation = p->v3->rotation = p->v4->rotation =
+ (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
+ p->v1->rotationSpeed = p->v2->rotationSpeed = p->v3->rotationSpeed = p->v4->rotationSpeed =
+ (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
+ p->v1->autoRotate = p->v2->autoRotate = p->v3->autoRotate = p->v4->autoRotate = m_autoRotation?1.0:0.0;
+ case Coloured:
+ //Color initialization
+ // Particle color
+ color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
+ color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
+ color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
+ color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
+ p->v1->color = p->v2->color = p->v3->color = p->v4->color = color;
+ default:
+ break;
}
-
- vertexCopy(p.v1, d->pv);
- vertexCopy(p.v2, d->pv);
- vertexCopy(p.v3, d->pv);
- vertexCopy(p.v4, d->pv);
+ vertexCopy(*p->v1, d->pv);
+ vertexCopy(*p->v2, d->pv);
+ vertexCopy(*p->v3, d->pv);
+ vertexCopy(*p->v4, d->pv);
}
QT_END_NAMESPACE