public void activateParticles (int startIndex, int count){ int currentTotaLife = life + (int)(lifeDiff * lifeValue.getScale(percent)), currentLife = currentTotaLife; int offsetTime = (int)(lifeOffset + lifeOffsetDiff * lifeOffsetValue.getScale(percent)); if (offsetTime > 0) { if (offsetTime >= currentLife) offsetTime = currentLife - 1; currentLife -= offsetTime; } float lifePercent = 1 - currentLife / (float)currentTotaLife; for(int i=startIndex*lifeChannel.strideSize, c = i +count*lifeChannel.strideSize; i < c; i+=lifeChannel.strideSize){ lifeChannel.data[i+ParticleChannels.CurrentLifeOffset] = currentLife; lifeChannel.data[i+ParticleChannels.TotalLifeOffset] = currentTotaLife; lifeChannel.data[i+ParticleChannels.LifePercentOffset] = lifePercent; } }
@Override public void update () { for(int i=0, accelOffset = 0, c = i +controller.particles.size *rotationChannel.strideSize; i < c; i +=rotationChannel.strideSize, accelOffset += accellerationChannel.strideSize){ Vector3 axisZ = TMP_V1.set( accellerationChannel.data[accelOffset +ParticleChannels.XOffset], accellerationChannel.data[accelOffset +ParticleChannels.YOffset], accellerationChannel.data[accelOffset +ParticleChannels.ZOffset]).nor(), axisY = TMP_V2.set(TMP_V1).crs(Vector3.Y).nor().crs(TMP_V1).nor(), axisX = TMP_V3.set(axisY).crs(axisZ).nor(); TMP_Q.setFromAxes(false, axisX.x, axisY.x, axisZ.x, axisX.y, axisY.y, axisZ.y, axisX.z, axisY.z, axisZ.z); rotationChannel.data[i +ParticleChannels.XOffset] = TMP_Q.x; rotationChannel.data[i +ParticleChannels.YOffset] = TMP_Q.y; rotationChannel.data[i +ParticleChannels.ZOffset] = TMP_Q.z; rotationChannel.data[i +ParticleChannels.WOffset] = TMP_Q.w; } }
@Override public void activateParticles (int startIndex, int count) { super.activateParticles(startIndex, count); float start, diff; for(int i=startIndex*angularChannel.strideSize, c = i +count*angularChannel.strideSize; i < c; i +=angularChannel.strideSize){ //Theta start = thetaValue.newLowValue(); diff = thetaValue.newHighValue(); if(!thetaValue.isRelative()) diff -= start; angularChannel.data[i + ParticleChannels.VelocityThetaStartOffset] = start; angularChannel.data[i + ParticleChannels.VelocityThetaDiffOffset] = diff; //Phi start = phiValue.newLowValue(); diff = phiValue.newHighValue(); if(!phiValue.isRelative()) diff -= start; angularChannel.data[i + ParticleChannels.VelocityPhiStartOffset] = start; angularChannel.data[i + ParticleChannels.VelocityPhiDiffOffset] = diff; } }
@Override public void update () { for(int i=0, l = ParticleChannels.LifePercentOffset, s =0, a = 0, c = i +controller.particles.size*directionalVelocityChannel.strideSize; i < c; s += strengthChannel.strideSize, i +=directionalVelocityChannel.strideSize, a += angularChannel.strideSize, l += lifeChannel.strideSize){ float lifePercent = lifeChannel.data[l], strength = strengthChannel.data[s + ParticleChannels.VelocityStrengthStartOffset] + strengthChannel.data[s + ParticleChannels.VelocityStrengthDiffOffset]* strengthValue.getScale(lifePercent), phi = angularChannel.data[a + ParticleChannels.VelocityPhiStartOffset] + angularChannel.data[a + ParticleChannels.VelocityPhiDiffOffset]* phiValue.getScale(lifePercent), theta = angularChannel.data[a + ParticleChannels.VelocityThetaStartOffset] + angularChannel.data[a + ParticleChannels.VelocityThetaDiffOffset]* thetaValue.getScale(lifePercent); float cosTheta = MathUtils.cosDeg(theta), sinTheta = MathUtils.sinDeg(theta), cosPhi = MathUtils.cosDeg(phi), sinPhi = MathUtils.sinDeg(phi); TMP_V3.set(cosTheta *sinPhi, cosPhi, sinTheta*sinPhi).nor().scl(strength); directionalVelocityChannel.data[i +ParticleChannels.XOffset] += TMP_V3.x; directionalVelocityChannel.data[i +ParticleChannels.YOffset] += TMP_V3.y; directionalVelocityChannel.data[i +ParticleChannels.ZOffset] += TMP_V3.z; } }
@Override public void update () { int lifeOffset=ParticleChannels.LifePercentOffset, strengthOffset = 0, forceOffset = 0; for(int i=0, c= controller.particles.size; i < c; ++i, strengthOffset += strengthChannel.strideSize, forceOffset +=accelerationChannel.strideSize, lifeOffset += lifeChannel.strideSize){ float strength = strengthChannel.data[strengthOffset + ParticleChannels.VelocityStrengthStartOffset] + strengthChannel.data[strengthOffset + ParticleChannels.VelocityStrengthDiffOffset]* strengthValue.getScale(lifeChannel.data[lifeOffset]); TMP_V3.set(MathUtils.random(-1, 1f), MathUtils.random(-1, 1f), MathUtils.random(-1, 1f)).nor().scl(strength); accelerationChannel.data[forceOffset +ParticleChannels.XOffset] += TMP_V3.x; accelerationChannel.data[forceOffset +ParticleChannels.YOffset] += TMP_V3.y; accelerationChannel.data[forceOffset +ParticleChannels.ZOffset] += TMP_V3.z; } }
@Override public void update () { for(int i=0, positionOffset = 0, c = controller.particles.size; i< c; ++i, positionOffset += positionChannel.strideSize){ ParticleController particleController = controllerChannel.data[i]; float scale = hasScale ? scaleChannel.data[i] : 1; float qx=0, qy=0, qz=0, qw=1; if(hasRotation){ int rotationOffset = i* rotationChannel.strideSize; qx = rotationChannel.data[rotationOffset + ParticleChannels.XOffset]; qy = rotationChannel.data[rotationOffset + ParticleChannels.YOffset]; qz = rotationChannel.data[rotationOffset + ParticleChannels.ZOffset]; qw = rotationChannel.data[rotationOffset + ParticleChannels.WOffset]; } particleController.setTransform( positionChannel.data[positionOffset + ParticleChannels.XOffset], positionChannel.data[positionOffset + ParticleChannels.YOffset], positionChannel.data[positionOffset + ParticleChannels.ZOffset], qx,qy,qz,qw, scale); particleController.update(); } }
@Override public void activateParticles (int startIndex, int count) { for(int i=startIndex*colorChannel.strideSize, a = startIndex*alphaInterpolationChannel.strideSize, l = startIndex*lifeChannel.strideSize + ParticleChannels.LifePercentOffset, c = i +count*colorChannel.strideSize; i < c; i +=colorChannel.strideSize, a +=alphaInterpolationChannel.strideSize, l +=lifeChannel.strideSize){ float alphaStart = alphaValue.newLowValue(); float alphaDiff = alphaValue.newHighValue() - alphaStart; colorValue.getColor(0, colorChannel.data, i); colorChannel.data[i+ParticleChannels.AlphaOffset] = alphaStart + alphaDiff*alphaValue.getScale(lifeChannel.data[l]); alphaInterpolationChannel.data[a+ParticleChannels.InterpolationStartOffset] = alphaStart; alphaInterpolationChannel.data[a+ParticleChannels.InterpolationDiffOffset] = alphaDiff; } }
@Override public void allocateChannels() { renderData.positionChannel = controller.particles.addChannel(ParticleChannels.Position); renderData.regionChannel = controller.particles.addChannel(ParticleChannels.TextureRegion, TextureRegionInitializer.get()); renderData.colorChannel = controller.particles.addChannel(ParticleChannels.Color, ColorInitializer.get()); renderData.scaleChannel = controller.particles.addChannel(ParticleChannels.Scale, ScaleInitializer.get()); renderData.rotationChannel = controller.particles.addChannel(ParticleChannels.Rotation2D, Rotation2dInitializer.get()); }
@Override protected void flush(int[] offsets) { int tp = 0; for (PointSpriteControllerRenderData data : renderData) { FloatChannel scaleChannel = data.scaleChannel; FloatChannel regionChannel = data.regionChannel; FloatChannel positionChannel = data.positionChannel; FloatChannel colorChannel = data.colorChannel; FloatChannel rotationChannel = data.rotationChannel; for (int p = 0; p < data.controller.particles.size; ++p, ++tp) { int offset = offsets[tp] * CPU_VERTEX_SIZE; int regionOffset = p * regionChannel.strideSize; int positionOffset = p * positionChannel.strideSize; int colorOffset = p * colorChannel.strideSize; int rotationOffset = p * rotationChannel.strideSize; vertices[offset + CPU_POSITION_OFFSET] = positionChannel.data[positionOffset + ParticleChannels.XOffset]; vertices[offset + CPU_POSITION_OFFSET + 1] = positionChannel.data[positionOffset + ParticleChannels.YOffset]; vertices[offset + CPU_POSITION_OFFSET + 2] = positionChannel.data[positionOffset + ParticleChannels.ZOffset]; vertices[offset + CPU_COLOR_OFFSET] = colorChannel.data[colorOffset + ParticleChannels.RedOffset]; vertices[offset + CPU_COLOR_OFFSET + 1] = colorChannel.data[colorOffset + ParticleChannels.GreenOffset]; vertices[offset + CPU_COLOR_OFFSET + 2] = colorChannel.data[colorOffset + ParticleChannels.BlueOffset]; vertices[offset + CPU_COLOR_OFFSET + 3] = colorChannel.data[colorOffset + ParticleChannels.AlphaOffset]; vertices[offset + CPU_SIZE_AND_ROTATION_OFFSET] = scaleChannel.data[p * scaleChannel.strideSize]; vertices[offset + CPU_SIZE_AND_ROTATION_OFFSET + 1] = rotationChannel.data[rotationOffset + ParticleChannels.CosineOffset]; vertices[offset + CPU_SIZE_AND_ROTATION_OFFSET + 2] = rotationChannel.data[rotationOffset + ParticleChannels.SineOffset]; vertices[offset + CPU_REGION_OFFSET] = regionChannel.data[regionOffset + ParticleChannels.UOffset]; vertices[offset + CPU_REGION_OFFSET + 1] = regionChannel.data[regionOffset + ParticleChannels.VOffset]; vertices[offset + CPU_REGION_OFFSET + 2] = regionChannel.data[regionOffset + ParticleChannels.U2Offset]; vertices[offset + CPU_REGION_OFFSET + 3] = regionChannel.data[regionOffset + ParticleChannels.V2Offset]; } } renderable.meshPart.size = bufferedParticlesCount; renderable.meshPart.mesh.setVertices(vertices, 0, bufferedParticlesCount * CPU_VERTEX_SIZE); renderable.meshPart.update(); }
@Override protected void flush(int[] offsets){ int tp = 0; for(PointSpriteControllerRenderData data: renderData){ FloatChannel scaleChannel = data.scaleChannel; FloatChannel regionChannel = data.regionChannel; FloatChannel positionChannel = data.positionChannel; FloatChannel colorChannel = data.colorChannel; FloatChannel rotationChannel = data.rotationChannel; for (int p = 0; p < data.controller.particles.size; ++p, ++tp) { int offset = offsets[tp]*CPU_VERTEX_SIZE; int regionOffset = p*regionChannel.strideSize; int positionOffset = p*positionChannel.strideSize; int colorOffset = p*colorChannel.strideSize; int rotationOffset = p*rotationChannel.strideSize; vertices[offset + CPU_POSITION_OFFSET] = positionChannel.data[positionOffset + ParticleChannels.XOffset]; vertices[offset + CPU_POSITION_OFFSET+1] = positionChannel.data[positionOffset + ParticleChannels.YOffset]; vertices[offset + CPU_POSITION_OFFSET+2] = positionChannel.data[positionOffset + ParticleChannels.ZOffset]; vertices[offset + CPU_COLOR_OFFSET] = colorChannel.data[colorOffset + ParticleChannels.RedOffset]; vertices[offset + CPU_COLOR_OFFSET+1] = colorChannel.data[colorOffset + ParticleChannels.GreenOffset]; vertices[offset + CPU_COLOR_OFFSET+2] = colorChannel.data[colorOffset + ParticleChannels.BlueOffset]; vertices[offset + CPU_COLOR_OFFSET+3] = colorChannel.data[colorOffset + ParticleChannels.AlphaOffset]; vertices[offset + CPU_SIZE_AND_ROTATION_OFFSET] = scaleChannel.data[p* scaleChannel.strideSize]; vertices[offset + CPU_SIZE_AND_ROTATION_OFFSET+1] = rotationChannel.data[rotationOffset + ParticleChannels.CosineOffset]; vertices[offset + CPU_SIZE_AND_ROTATION_OFFSET+2] = rotationChannel.data[rotationOffset + ParticleChannels.SineOffset]; vertices[offset + CPU_REGION_OFFSET] = regionChannel.data[regionOffset + ParticleChannels.UOffset]; vertices[offset + CPU_REGION_OFFSET+1] = regionChannel.data[regionOffset + ParticleChannels.VOffset]; vertices[offset + CPU_REGION_OFFSET+2] = regionChannel.data[regionOffset + ParticleChannels.U2Offset]; vertices[offset + CPU_REGION_OFFSET+3] = regionChannel.data[regionOffset + ParticleChannels.V2Offset]; } } renderable.meshPartSize = bufferedParticlesCount; renderable.mesh.setVertices(vertices, 0, bufferedParticlesCount*CPU_VERTEX_SIZE); }
@Override public void activateParticles (int startIndex, int count) { for(int i=startIndex*positionChannel.strideSize, c = i +count*positionChannel.strideSize; i < c; i +=positionChannel.strideSize){ spawnShapeValue.spawn(TMP_V1, controller.emitter.percent); TMP_V1.mul(controller.transform); positionChannel.data[i+ParticleChannels.XOffset] = TMP_V1.x; positionChannel.data[i+ParticleChannels.YOffset] = TMP_V1.y; positionChannel.data[i+ParticleChannels.ZOffset] = TMP_V1.z; } }
@Override public void allocateChannels() { for(int k=0; k < velocities.size; ++k){ velocities.items[k].allocateChannels(); } //Hack, shouldn't be done but after all the modifiers allocated their channels //it's possible to check if we need to allocate previous position channel accellerationChannel = controller.particles.getChannel(ParticleChannels.Acceleration); hasAcceleration = accellerationChannel != null; if(hasAcceleration){ positionChannel = controller.particles.addChannel(ParticleChannels.Position); previousPositionChannel = controller.particles.addChannel(ParticleChannels.PreviousPosition); } //Angular velocity check angularVelocityChannel = controller.particles.getChannel(ParticleChannels.AngularVelocity2D); has2dAngularVelocity = angularVelocityChannel != null; if(has2dAngularVelocity){ rotationChannel = controller.particles.addChannel(ParticleChannels.Rotation2D); has3dAngularVelocity = false; } else{ angularVelocityChannel = controller.particles.getChannel(ParticleChannels.AngularVelocity3D); has3dAngularVelocity = angularVelocityChannel != null; if(has3dAngularVelocity) rotationChannel = controller.particles.addChannel(ParticleChannels.Rotation3D); } }
public void activateParticles (int startIndex, int count) { if(hasAcceleration){ //Previous position is the current position //Attention, this requires that some other influencer setting the position channel must execute before this influencer. for(int i=startIndex*positionChannel.strideSize, c = i +count*positionChannel.strideSize; i< c; i+= positionChannel.strideSize){ previousPositionChannel.data[i+ParticleChannels.XOffset] = positionChannel.data[i+ParticleChannels.XOffset]; previousPositionChannel.data[i+ParticleChannels.YOffset] = positionChannel.data[i+ParticleChannels.YOffset]; previousPositionChannel.data[i+ParticleChannels.ZOffset] = positionChannel.data[i+ParticleChannels.ZOffset]; /* //Euler intialization previousPositionChannel.data[i+ParticleChannels.XOffset] = previousPositionChannel.data[i+ParticleChannels.YOffset] = previousPositionChannel.data[i+ParticleChannels.ZOffset] = 0; */ } } if(has2dAngularVelocity){ //Rotation back to 0 for(int i=startIndex*rotationChannel.strideSize, c = i +count*rotationChannel.strideSize; i< c; i+= rotationChannel.strideSize){ rotationChannel.data[i+ParticleChannels.CosineOffset] = 1; rotationChannel.data[i+ParticleChannels.SineOffset] = 0; } } else if(has3dAngularVelocity){ //Rotation back to 0 for(int i=startIndex*rotationChannel.strideSize, c = i +count*rotationChannel.strideSize; i< c; i+= rotationChannel.strideSize){ rotationChannel.data[i+ParticleChannels.XOffset] = 0; rotationChannel.data[i+ParticleChannels.YOffset] = 0; rotationChannel.data[i+ParticleChannels.ZOffset] = 0; rotationChannel.data[i+ParticleChannels.WOffset] = 1; } } for(int k=0; k < velocities.size; ++k){ velocities.items[k].activateParticles(startIndex, count); } }
@Override public void activateParticles (int startIndex, int count) { float start, diff; for(int i=startIndex*strengthChannel.strideSize, c = i +count*strengthChannel.strideSize; i < c; i +=strengthChannel.strideSize){ start = strengthValue.newLowValue(); diff = strengthValue.newHighValue(); if(!strengthValue.isRelative()) diff -= start; strengthChannel.data[i + ParticleChannels.VelocityStrengthStartOffset] = start; strengthChannel.data[i + ParticleChannels.VelocityStrengthDiffOffset] = diff; } }
@Override public void update () { for(int i=0, l = ParticleChannels.LifePercentOffset, s =0, c = i +controller.particles.size*rotationalVelocity2dChannel.strideSize; i < c; s += strengthChannel.strideSize, i +=rotationalVelocity2dChannel.strideSize, l +=lifeChannel.strideSize){ rotationalVelocity2dChannel.data[i] += strengthChannel.data[s + ParticleChannels.VelocityStrengthStartOffset] + strengthChannel.data[s + ParticleChannels.VelocityStrengthDiffOffset]* strengthValue.getScale(lifeChannel.data[l]); } }
@Override public void update () { float cx = 0, cy = 0, cz = 0; if(!isGlobal){ float[] val = controller.transform.val; cx = val[Matrix4.M03]; cy = val[Matrix4.M13]; cz = val[Matrix4.M23]; } int lifeOffset=ParticleChannels.LifePercentOffset, strengthOffset = 0, positionOffset = 0, forceOffset = 0; for(int i=0, c= controller.particles.size; i < c; ++i, positionOffset += positionChannel.strideSize, strengthOffset += strengthChannel.strideSize, forceOffset +=accelerationChannel.strideSize, lifeOffset += lifeChannel.strideSize){ float strength = strengthChannel.data[strengthOffset + ParticleChannels.VelocityStrengthStartOffset] + strengthChannel.data[strengthOffset + ParticleChannels.VelocityStrengthDiffOffset]* strengthValue.getScale(lifeChannel.data[lifeOffset]); TMP_V3.set( positionChannel.data[positionOffset +ParticleChannels.XOffset] -cx, positionChannel.data[positionOffset +ParticleChannels.YOffset] -cy, positionChannel.data[positionOffset +ParticleChannels.ZOffset] -cz) .nor().scl(strength); accelerationChannel.data[forceOffset +ParticleChannels.XOffset] += TMP_V3.x; accelerationChannel.data[forceOffset +ParticleChannels.YOffset] += TMP_V3.y; accelerationChannel.data[forceOffset +ParticleChannels.ZOffset] += TMP_V3.z; } }
@Override public void update () { for(int i=0, l = ParticleChannels.LifePercentOffset, s =0, a = 0, positionOffset = 0, c = i +controller.particles.size*directionalVelocityChannel.strideSize; i < c; s += strengthChannel.strideSize, i +=directionalVelocityChannel.strideSize, a += angularChannel.strideSize, l += lifeChannel.strideSize, positionOffset += positionChannel.strideSize ){ float lifePercent = lifeChannel.data[l], strength = strengthChannel.data[s + ParticleChannels.VelocityStrengthStartOffset] + strengthChannel.data[s + ParticleChannels.VelocityStrengthDiffOffset]* strengthValue.getScale(lifePercent), phi = angularChannel.data[a + ParticleChannels.VelocityPhiStartOffset] + angularChannel.data[a + ParticleChannels.VelocityPhiDiffOffset]* phiValue.getScale(lifePercent), theta = angularChannel.data[a + ParticleChannels.VelocityThetaStartOffset] + angularChannel.data[a + ParticleChannels.VelocityThetaDiffOffset]* thetaValue.getScale(lifePercent); float cosTheta = MathUtils.cosDeg(theta), sinTheta = MathUtils.sinDeg(theta), cosPhi = MathUtils.cosDeg(phi), sinPhi = MathUtils.sinDeg(phi); TMP_V3.set(cosTheta *sinPhi, cosPhi, sinTheta*sinPhi) .crs( positionChannel.data[positionOffset +ParticleChannels.XOffset], positionChannel.data[positionOffset +ParticleChannels.YOffset], positionChannel.data[positionOffset +ParticleChannels.ZOffset]) .nor().scl(strength); directionalVelocityChannel.data[i +ParticleChannels.XOffset] += TMP_V3.x; directionalVelocityChannel.data[i +ParticleChannels.YOffset] += TMP_V3.y; directionalVelocityChannel.data[i +ParticleChannels.ZOffset] += TMP_V3.z; } }
@Override public void init () { controllerChannel = controller.particles.getChannel(ParticleChannels.ParticleController); if(controllerChannel == null) throw new GdxRuntimeException("ParticleController channel not found, specify an influencer which will allocate it please."); scaleChannel = controller.particles.getChannel(ParticleChannels.Scale); rotationChannel = controller.particles.getChannel(ParticleChannels.Rotation3D); hasScale = scaleChannel != null; hasRotation = rotationChannel != null; }
@Override public void init () { AspectTextureRegion region = regions.items[0]; for(int i=0, c = controller.emitter.maxParticleCount*regionChannel.strideSize; i < c; i +=regionChannel.strideSize){ regionChannel.data[i +ParticleChannels.UOffset] = region.u; regionChannel.data[i +ParticleChannels.VOffset] = region.v; regionChannel.data[i +ParticleChannels.U2Offset] = region.u2; regionChannel.data[i +ParticleChannels.V2Offset] = region.v2; regionChannel.data[i +ParticleChannels.HalfWidthOffset] = 0.5f; regionChannel.data[i +ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; } }
@Override public void activateParticles (int startIndex, int count) { for(int i=startIndex*regionChannel.strideSize, c = i +count*regionChannel.strideSize; i < c; i +=regionChannel.strideSize){ AspectTextureRegion region = regions.random(); regionChannel.data[i +ParticleChannels.UOffset] = region.u; regionChannel.data[i +ParticleChannels.VOffset] = region.v; regionChannel.data[i +ParticleChannels.U2Offset] = region.u2; regionChannel.data[i +ParticleChannels.V2Offset] = region.v2; regionChannel.data[i +ParticleChannels.HalfWidthOffset] = 0.5f; regionChannel.data[i +ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; } }
@Override public void update () { for(int i=0, l = ParticleChannels.LifePercentOffset, c = controller.particles.size*regionChannel.strideSize; i < c; i +=regionChannel.strideSize, l +=lifeChannel.strideSize){ AspectTextureRegion region = regions.get( (int)(lifeChannel.data[l]*(regions.size-1))); regionChannel.data[i +ParticleChannels.UOffset] = region.u; regionChannel.data[i +ParticleChannels.VOffset] = region.v; regionChannel.data[i +ParticleChannels.U2Offset] = region.u2; regionChannel.data[i +ParticleChannels.V2Offset] = region.v2; regionChannel.data[i +ParticleChannels.HalfWidthOffset] = 0.5f; regionChannel.data[i +ParticleChannels.HalfHeightOffset] = region.halfInvAspectRatio; } }
@Override public void allocateChannels() { valueChannel = controller.particles.addChannel(valueChannelDescriptor); ParticleChannels.Interpolation.id = controller.particleChannels.newId(); interpolationChannel = controller.particles.addChannel(ParticleChannels.Interpolation); lifeChannel = controller.particles.addChannel(ParticleChannels.Life); }
@Override public void update () { for(int i=0, a = 0, l = ParticleChannels.LifePercentOffset, c = i +controller.particles.size*valueChannel.strideSize; i < c; i +=valueChannel.strideSize, a +=interpolationChannel.strideSize, l +=lifeChannel.strideSize){ valueChannel.data[i] = interpolationChannel.data[a +ParticleChannels.InterpolationStartOffset] + interpolationChannel.data[a +ParticleChannels.InterpolationDiffOffset] * value.getScale(lifeChannel.data[l]); } }
@Override public void activateParticles (int startIndex, int count) { for(int i=startIndex*colorChannel.strideSize, c = i +count*colorChannel.strideSize; i < c; i +=colorChannel.strideSize){ colorChannel.data[i+ParticleChannels.RedOffset] = MathUtils.random(); colorChannel.data[i+ParticleChannels.GreenOffset] = MathUtils.random(); colorChannel.data[i+ParticleChannels.BlueOffset] = MathUtils.random(); colorChannel.data[i+ParticleChannels.AlphaOffset] = MathUtils.random(); } }
@Override public void allocateChannels () { super.allocateChannels(); //Hack this allows to share the channel descriptor structure but using a different id temporary ParticleChannels.Interpolation.id = controller.particleChannels.newId(); alphaInterpolationChannel = controller.particles.addChannel(ParticleChannels.Interpolation); lifeChannel = controller.particles.addChannel(ParticleChannels.Life); }
@Override public void update () { for(int i=0, a = 0, l = ParticleChannels.LifePercentOffset, c = i +controller.particles.size*colorChannel.strideSize; i < c; i +=colorChannel.strideSize, a +=alphaInterpolationChannel.strideSize, l +=lifeChannel.strideSize){ float lifePercent = lifeChannel.data[l]; colorValue.getColor(lifePercent, colorChannel.data, i); colorChannel.data[i+ParticleChannels.AlphaOffset] = alphaInterpolationChannel.data[a+ParticleChannels.InterpolationStartOffset] + alphaInterpolationChannel.data[a+ParticleChannels.InterpolationDiffOffset] *alphaValue.getScale(lifePercent); } }
@Override public void allocateChannels () { renderData.positionChannel = controller.particles.addChannel(ParticleChannels.Position); renderData.regionChannel = controller.particles.addChannel(ParticleChannels.TextureRegion, TextureRegionInitializer.get()); renderData.colorChannel = controller.particles.addChannel(ParticleChannels.Color, ColorInitializer.get()); renderData.scaleChannel = controller.particles.addChannel(ParticleChannels.Scale, ScaleInitializer.get()); renderData.rotationChannel = controller.particles.addChannel(ParticleChannels.Rotation2D, Rotation2dInitializer.get()); }
@Override public void init () { renderData.modelInstanceChannel = controller.particles.getChannel(ParticleChannels.ModelInstance); renderData.colorChannel = controller.particles.getChannel(ParticleChannels.Color); renderData.scaleChannel = controller.particles.getChannel(ParticleChannels.Scale); renderData.rotationChannel = controller.particles.getChannel(ParticleChannels.Rotation3D); hasColor = renderData.colorChannel != null; hasScale = renderData.scaleChannel != null; hasRotation = renderData.rotationChannel != null; }
@Override public void update () { for(int i=0, positionOffset = 0, c = controller.particles.size; i< c; ++i, positionOffset += renderData.positionChannel.strideSize){ ModelInstance instance = renderData.modelInstanceChannel.data[i]; float scale = hasScale ? renderData.scaleChannel.data[i] : 1; float qx=0, qy=0, qz=0, qw=1; if(hasRotation){ int rotationOffset = i* renderData.rotationChannel.strideSize; qx = renderData.rotationChannel.data[rotationOffset + ParticleChannels.XOffset]; qy = renderData.rotationChannel.data[rotationOffset + ParticleChannels.YOffset]; qz = renderData.rotationChannel.data[rotationOffset + ParticleChannels.ZOffset]; qw = renderData.rotationChannel.data[rotationOffset + ParticleChannels.WOffset]; } instance.transform.set( renderData.positionChannel.data[positionOffset + ParticleChannels.XOffset], renderData.positionChannel.data[positionOffset + ParticleChannels.YOffset], renderData.positionChannel.data[positionOffset + ParticleChannels.ZOffset], qx, qy, qz, qw, scale, scale, scale); if(hasColor){ int colorOffset = i*renderData.colorChannel.strideSize; ColorAttribute colorAttribute = (ColorAttribute)instance.materials.get(0).get(ColorAttribute.Diffuse); BlendingAttribute blendingAttribute = (BlendingAttribute)instance.materials.get(0).get(BlendingAttribute.Type); colorAttribute.color.r = renderData.colorChannel.data[colorOffset +ParticleChannels.RedOffset]; colorAttribute.color.g = renderData.colorChannel.data[colorOffset +ParticleChannels.GreenOffset]; colorAttribute.color.b = renderData.colorChannel.data[colorOffset +ParticleChannels.BlueOffset]; if(blendingAttribute != null) blendingAttribute.opacity = renderData.colorChannel.data[colorOffset +ParticleChannels.AlphaOffset]; } } super.update(); }
private void fillVerticesGPU (int[] particlesOffset) { int tp=0; for(BillboardControllerRenderData data : renderData){ FloatChannel scaleChannel = data.scaleChannel; FloatChannel regionChannel = data.regionChannel; FloatChannel positionChannel = data.positionChannel; FloatChannel colorChannel = data.colorChannel; FloatChannel rotationChannel = data.rotationChannel; for(int p=0, c = data.controller.particles.size; p < c; ++p, ++tp){ int baseOffset = particlesOffset[tp]*currentVertexSize*4; float scale = scaleChannel.data[p* scaleChannel.strideSize]; int regionOffset = p*regionChannel.strideSize; int positionOffset = p*positionChannel.strideSize; int colorOffset = p*colorChannel.strideSize; int rotationOffset = p*rotationChannel.strideSize; float px = positionChannel.data[positionOffset + ParticleChannels.XOffset], py = positionChannel.data[positionOffset + ParticleChannels.YOffset], pz = positionChannel.data[positionOffset + ParticleChannels.ZOffset]; float u = regionChannel.data[regionOffset +ParticleChannels.UOffset]; float v = regionChannel.data[regionOffset +ParticleChannels.VOffset]; float u2 = regionChannel.data[regionOffset +ParticleChannels.U2Offset]; float v2 = regionChannel.data[regionOffset +ParticleChannels.V2Offset]; float sx = regionChannel.data[regionOffset +ParticleChannels.HalfWidthOffset] * scale, sy = regionChannel.data[regionOffset+ParticleChannels.HalfHeightOffset] * scale; float r = colorChannel.data[colorOffset +ParticleChannels.RedOffset]; float g = colorChannel.data[colorOffset +ParticleChannels.GreenOffset]; float b = colorChannel.data[colorOffset +ParticleChannels.BlueOffset]; float a = colorChannel.data[colorOffset +ParticleChannels.AlphaOffset]; float cosRotation = rotationChannel.data[rotationOffset +ParticleChannels.CosineOffset]; float sinRotation = rotationChannel.data[rotationOffset +ParticleChannels.SineOffset]; //bottom left, bottom right, top right, top left putVertex(vertices, baseOffset, px, py, pz, u, v2, -sx, -sy, cosRotation, sinRotation, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, px, py, pz, u2, v2, sx, -sy, cosRotation, sinRotation, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, px, py, pz, u2, v, sx, sy, cosRotation, sinRotation, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, px, py, pz, u, v, -sx, sy, cosRotation, sinRotation, r, g, b, a); baseOffset += currentVertexSize; } } }
private void fillVerticesToViewPointCPU (int[] particlesOffset) { int tp=0; for(BillboardControllerRenderData data : renderData){ FloatChannel scaleChannel = data.scaleChannel; FloatChannel regionChannel = data.regionChannel; FloatChannel positionChannel = data.positionChannel; FloatChannel colorChannel = data.colorChannel; FloatChannel rotationChannel = data.rotationChannel; for(int p=0, c = data.controller.particles.size; p < c; ++p, ++tp){ int baseOffset = particlesOffset[tp]*currentVertexSize*4; float scale = scaleChannel.data[p* scaleChannel.strideSize]; int regionOffset = p*regionChannel.strideSize; int positionOffset = p*positionChannel.strideSize; int colorOffset = p*colorChannel.strideSize; int rotationOffset = p*rotationChannel.strideSize; float px = positionChannel.data[positionOffset + ParticleChannels.XOffset], py = positionChannel.data[positionOffset + ParticleChannels.YOffset], pz = positionChannel.data[positionOffset + ParticleChannels.ZOffset]; float u = regionChannel.data[regionOffset +ParticleChannels.UOffset]; float v = regionChannel.data[regionOffset +ParticleChannels.VOffset]; float u2 = regionChannel.data[regionOffset +ParticleChannels.U2Offset]; float v2 = regionChannel.data[regionOffset +ParticleChannels.V2Offset]; float sx = regionChannel.data[regionOffset +ParticleChannels.HalfWidthOffset] * scale, sy = regionChannel.data[regionOffset+ParticleChannels.HalfHeightOffset] * scale; float r = colorChannel.data[colorOffset +ParticleChannels.RedOffset]; float g = colorChannel.data[colorOffset +ParticleChannels.GreenOffset]; float b = colorChannel.data[colorOffset +ParticleChannels.BlueOffset]; float a = colorChannel.data[colorOffset +ParticleChannels.AlphaOffset]; float cosRotation = rotationChannel.data[rotationOffset +ParticleChannels.CosineOffset]; float sinRotation = rotationChannel.data[rotationOffset +ParticleChannels.SineOffset]; Vector3 look = TMP_V3.set(camera.position).sub(px, py, pz).nor(), //normal right = TMP_V1.set(camera.up).crs(look).nor(), //tangent up = TMP_V2.set(look).crs(right); right.scl(sx); up.scl(sy); if(cosRotation != 1){ TMP_M3.setToRotation(look, cosRotation, sinRotation); putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x, -TMP_V1.y-TMP_V2.y, -TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v2, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x-TMP_V2.x, TMP_V1.y-TMP_V2.y, TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v2, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x+TMP_V2.x, TMP_V1.y+TMP_V2.y, TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x, -TMP_V1.y+TMP_V2.y, -TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v, r, g, b, a); } else { putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x+px, -TMP_V1.y-TMP_V2.y+py, -TMP_V1.z-TMP_V2.z+pz), u, v2, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x-TMP_V2.x+px, TMP_V1.y-TMP_V2.y+py, TMP_V1.z-TMP_V2.z+pz), u2, v2, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x+TMP_V2.x+px, TMP_V1.y+TMP_V2.y+py, TMP_V1.z+TMP_V2.z+pz), u2, v, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x+px, -TMP_V1.y+TMP_V2.y+py, -TMP_V1.z+TMP_V2.z+pz), u, v, r, g, b, a); } } } }
private void fillVerticesToScreenCPU (int[] particlesOffset) { Vector3 look = TMP_V3.set(camera.direction).scl(-1), //normal right = TMP_V4.set(camera.up).crs(look).nor(), //tangent up = camera.up; int tp=0; for(BillboardControllerRenderData data : renderData){ FloatChannel scaleChannel = data.scaleChannel; FloatChannel regionChannel = data.regionChannel; FloatChannel positionChannel = data.positionChannel; FloatChannel colorChannel = data.colorChannel; FloatChannel rotationChannel = data.rotationChannel; for(int p=0, c = data.controller.particles.size; p < c; ++p, ++tp){ int baseOffset = particlesOffset[tp]*currentVertexSize*4; float scale = scaleChannel.data[p* scaleChannel.strideSize]; int regionOffset = p*regionChannel.strideSize; int positionOffset = p*positionChannel.strideSize; int colorOffset = p*colorChannel.strideSize; int rotationOffset = p*rotationChannel.strideSize; float px = positionChannel.data[positionOffset + ParticleChannels.XOffset], py = positionChannel.data[positionOffset + ParticleChannels.YOffset], pz = positionChannel.data[positionOffset + ParticleChannels.ZOffset]; float u = regionChannel.data[regionOffset +ParticleChannels.UOffset]; float v = regionChannel.data[regionOffset +ParticleChannels.VOffset]; float u2 = regionChannel.data[regionOffset +ParticleChannels.U2Offset]; float v2 = regionChannel.data[regionOffset +ParticleChannels.V2Offset]; float sx = regionChannel.data[regionOffset +ParticleChannels.HalfWidthOffset] * scale, sy = regionChannel.data[regionOffset+ParticleChannels.HalfHeightOffset] * scale; float r = colorChannel.data[colorOffset +ParticleChannels.RedOffset]; float g = colorChannel.data[colorOffset +ParticleChannels.GreenOffset]; float b = colorChannel.data[colorOffset +ParticleChannels.BlueOffset]; float a = colorChannel.data[colorOffset +ParticleChannels.AlphaOffset]; float cosRotation = rotationChannel.data[rotationOffset +ParticleChannels.CosineOffset]; float sinRotation = rotationChannel.data[rotationOffset +ParticleChannels.SineOffset]; TMP_V1.set(right).scl(sx); TMP_V2.set(up).scl(sy); if(cosRotation != 1){ TMP_M3.setToRotation(look, cosRotation, sinRotation); putVertex( vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x, -TMP_V1.y-TMP_V2.y, -TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v2, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x-TMP_V2.x, TMP_V1.y-TMP_V2.y, TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v2, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x+TMP_V2.x, TMP_V1.y+TMP_V2.y, TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x, -TMP_V1.y+TMP_V2.y, -TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v, r, g, b, a); } else { putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x+px, -TMP_V1.y-TMP_V2.y+py, -TMP_V1.z-TMP_V2.z+pz), u, v2, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x-TMP_V2.x+px, TMP_V1.y-TMP_V2.y+py, TMP_V1.z-TMP_V2.z+pz), u2, v2, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x+TMP_V2.x+px, TMP_V1.y+TMP_V2.y+py, TMP_V1.z+TMP_V2.z+pz), u2, v, r, g, b, a); baseOffset += currentVertexSize; putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x+px, -TMP_V1.y+TMP_V2.y+py, -TMP_V1.z+TMP_V2.z+pz), u, v, r, g, b, a); } } } }
@Override public void allocateChannels() { lifeChannel = controller.particles.addChannel(ParticleChannels.Life); }
public void update () { int deltaMillis = (int)(controller.deltaTime * 1000); if (delayTimer < delay) { delayTimer += deltaMillis; } else { boolean emit = emissionMode != EmissionMode.Disabled; //End check if (durationTimer < duration) { durationTimer += deltaMillis; percent = durationTimer / (float)duration; } else { if (continuous && emit && emissionMode == EmissionMode.Enabled) controller.start(); else emit = false; } if(emit) { //Emit particles emissionDelta += deltaMillis; float emissionTime = emission + emissionDiff * emissionValue.getScale(percent); if (emissionTime > 0) { emissionTime = 1000 / emissionTime; if (emissionDelta >= emissionTime) { int emitCount = (int)(emissionDelta / emissionTime); emitCount = Math.min(emitCount, maxParticleCount - controller.particles.size); emissionDelta -= emitCount * emissionTime; emissionDelta %= emissionTime; addParticles(emitCount); } } if (controller.particles.size < minParticleCount) addParticles(minParticleCount - controller.particles.size); } } //Update particles int activeParticles = controller.particles.size; for (int i = 0, k=0; i < controller.particles.size; ) { if ( (lifeChannel.data[k+ParticleChannels.CurrentLifeOffset] -= deltaMillis) <= 0) { controller.particles.removeElement(i); continue; } else { lifeChannel.data[k+ParticleChannels.LifePercentOffset] = 1- lifeChannel.data[k+ParticleChannels.CurrentLifeOffset]/lifeChannel.data[k+ParticleChannels.TotalLifeOffset]; } ++i; k+=lifeChannel.strideSize; } if(controller.particles.size < activeParticles){ controller.killParticles(controller.particles.size, activeParticles - controller.particles.size); } }
@Override public void allocateChannels () { positionChannel = controller.particles.addChannel(ParticleChannels.Position); }
public void update(){ //Clean previouse frame velocities if(hasAcceleration) Arrays.fill(accellerationChannel.data, 0, controller.particles.size*accellerationChannel.strideSize, 0); if(has2dAngularVelocity || has3dAngularVelocity) Arrays.fill(angularVelocityChannel.data, 0, controller.particles.size*angularVelocityChannel.strideSize, 0); //Sum all the forces/accelerations for(int k=0; k < velocities.size; ++k){ velocities.items[k].update(); } //Apply the forces if(hasAcceleration){ /* //Euler Integration for(int i=0, offset = 0; i < controller.particles.size; ++i, offset +=positionChannel.strideSize){ previousPositionChannel.data[offset + ParticleChannels.XOffset] += accellerationChannel.data[offset + ParticleChannels.XOffset]*controller.deltaTime; previousPositionChannel.data[offset + ParticleChannels.YOffset] += accellerationChannel.data[offset + ParticleChannels.YOffset]*controller.deltaTime; previousPositionChannel.data[offset + ParticleChannels.ZOffset] += accellerationChannel.data[offset + ParticleChannels.ZOffset]*controller.deltaTime; positionChannel.data[offset + ParticleChannels.XOffset] += previousPositionChannel.data[offset + ParticleChannels.XOffset]*controller.deltaTime; positionChannel.data[offset + ParticleChannels.YOffset] += previousPositionChannel.data[offset + ParticleChannels.YOffset]*controller.deltaTime; positionChannel.data[offset + ParticleChannels.ZOffset] += previousPositionChannel.data[offset + ParticleChannels.ZOffset]*controller.deltaTime; } */ //Verlet integration for(int i=0, offset = 0; i < controller.particles.size; ++i, offset +=positionChannel.strideSize){ float x = positionChannel.data[offset + ParticleChannels.XOffset], y = positionChannel.data[offset + ParticleChannels.YOffset], z = positionChannel.data[offset + ParticleChannels.ZOffset]; positionChannel.data[offset + ParticleChannels.XOffset] = 2*x - previousPositionChannel.data[offset + ParticleChannels.XOffset] + accellerationChannel.data[offset + ParticleChannels.XOffset]*controller.deltaTimeSqr; positionChannel.data[offset + ParticleChannels.YOffset] = 2*y- previousPositionChannel.data[offset + ParticleChannels.YOffset] + accellerationChannel.data[offset + ParticleChannels.YOffset]*controller.deltaTimeSqr; positionChannel.data[offset + ParticleChannels.ZOffset] = 2*z - previousPositionChannel.data[offset + ParticleChannels.ZOffset] + accellerationChannel.data[offset + ParticleChannels.ZOffset]*controller.deltaTimeSqr; previousPositionChannel.data[offset + ParticleChannels.XOffset] = x; previousPositionChannel.data[offset + ParticleChannels.YOffset] = y; previousPositionChannel.data[offset + ParticleChannels.ZOffset] = z; } } if(has2dAngularVelocity){ for(int i=0, offset = 0; i < controller.particles.size; ++i, offset +=rotationChannel.strideSize){ float rotation = angularVelocityChannel.data[i]*controller.deltaTime; if(rotation != 0){ float cosBeta = MathUtils.cosDeg(rotation), sinBeta = MathUtils.sinDeg(rotation); float currentCosine = rotationChannel.data[offset + ParticleChannels.CosineOffset]; float currentSine = rotationChannel.data[offset + ParticleChannels.SineOffset]; float newCosine = currentCosine*cosBeta - currentSine*sinBeta, newSine = currentSine*cosBeta + currentCosine*sinBeta; rotationChannel.data[offset + ParticleChannels.CosineOffset] = newCosine; rotationChannel.data[offset + ParticleChannels.SineOffset] = newSine; } } } else if(has3dAngularVelocity){ for(int i=0, offset = 0, angularOffset = 0; i < controller.particles.size; ++i, offset +=rotationChannel.strideSize, angularOffset += angularVelocityChannel.strideSize){ float wx = angularVelocityChannel.data[angularOffset + ParticleChannels.XOffset], wy = angularVelocityChannel.data[angularOffset + ParticleChannels.YOffset], wz = angularVelocityChannel.data[angularOffset + ParticleChannels.ZOffset], qx = rotationChannel.data[offset + ParticleChannels.XOffset], qy = rotationChannel.data[offset + ParticleChannels.YOffset], qz = rotationChannel.data[offset + ParticleChannels.ZOffset], qw = rotationChannel.data[offset + ParticleChannels.WOffset]; TMP_Q.set(wx, wy, wz, 0).mul(qx, qy, qz, qw).mul(0.5f*controller.deltaTime).add(qx, qy, qz, qw).nor(); rotationChannel.data[offset + ParticleChannels.XOffset] = TMP_Q.x; rotationChannel.data[offset + ParticleChannels.YOffset] = TMP_Q.y; rotationChannel.data[offset + ParticleChannels.ZOffset] = TMP_Q.z; rotationChannel.data[offset + ParticleChannels.WOffset] = TMP_Q.w; } } }
@Override public void allocateChannels() { rotationChannel = controller.particles.addChannel(ParticleChannels.Rotation3D); accellerationChannel = controller.particles.addChannel(ParticleChannels.Acceleration); }
@Override public void allocateChannels() { super.allocateChannels(); ParticleChannels.Interpolation.id = controller.particleChannels.newId(); strengthChannel = controller.particles.addChannel(ParticleChannels.Interpolation); }
@Override public void allocateChannels() { super.allocateChannels(); ParticleChannels.Interpolation4.id = controller.particleChannels.newId(); angularChannel = controller.particles.addChannel(ParticleChannels.Interpolation4); }