/// <summary> /// Render all the particles in the emitter. This method is called by particle effects /// and should not normally be called otherwise. /// </summary> /// <param name="vertexScratch">Scratch space for vertices. Must contain enough space for all particles to be rendered.</param> /// <param name="vertexOffset">Offset into vertex scratch space for first vertex. Will be udpated for later particles.</param> /// <param name="textureCoords">Array of texture coords.</param> /// <param name="normal">Precomputed normal for particle.</param> /// <param name="tangent">Precomputed tangent for particle.</param> public void RenderEmitter(GFXVertexFormat.PCTTBN[] vertexScratch, ref int vertexOffset, Vector2[] textureCoords, ref Vector4 normal, ref Vector4 tangent) { // Any emitter-data or Allocated Particles? if (CurrentEmitterData == null || Allocated == 0) return; // Sanity! Assert.Fatal(Head != T2DParticleManager.NodeEndMarker, "Particles allocated but none in emitter chain!"); // Fetch Particle Manager Pool. T2DParticle[] particleManagerPool = T2DParticleManager.Instance.Pool; // Fetch Particle Count. int particleCount = Allocated; // Note Vertex base. int vertexBase = vertexOffset; // Fetch current index. int currentIndex = CurrentEmitterData.FirstInFrontOrder ? Tail : Head; // no need to dereference these more than once Vector2 pivot = _emitterData.ParticlePivotPoint; T2DKeyGraph redLife = _emitterData.RedChannelLife; T2DKeyGraph greenLife = _emitterData.GreenChannelLife; T2DKeyGraph blueLife = _emitterData.BlueChannelLife; T2DKeyGraph visibilityLife = _emitterData.VisibilityLife; T2DKeyGraph visibilityScale = _parentEffect.CurrentEffectData.VisibilityScale; // Iterate all allocated particles. while (currentIndex != -1) { // Calculate Particle unit-age, so that we can get size float unitAge = particleManagerPool[currentIndex].Age / particleManagerPool[currentIndex].Lifetime; // Scale Size //Vector2 renderSize = 0.5f * particleManagerPool[currentIndex]._size; Vector2 renderSize; Vector2.Multiply(ref particleManagerPool[currentIndex]._size, 0.5f, out renderSize); renderSize.X *= _emitterData.SizeXLife[unitAge]; if (renderSize.X < 0.0f) renderSize.X = 0.0f; if (_emitterData.FixedParticleAspect) renderSize.Y = renderSize.X; else { renderSize.Y *= _emitterData.SizeYLife[unitAge]; if (renderSize.Y < 0.0f) renderSize.Y = 0.0f; } // Transform Particle, inline the math. Rotation2D rotation = new Rotation2D(MathHelper.ToRadians(particleManagerPool[currentIndex]._rotationAngle)); //Vector2 center = particleManagerPool[currentIndex]._position + renderSize * pivot - rotation.Rotate(renderSize * pivot); Vector2 center; Vector2.Multiply(ref renderSize, ref pivot, out center); Vector2 rotate = rotation.Rotate(center); Vector2.Subtract(ref center, ref rotate, out center); Vector2.Add(ref particleManagerPool[currentIndex]._position, ref center, out center); //Vector2 x = renderSize.X * rotation.X; //Vector2 y = renderSize.Y * rotation.Y; Vector2 x, y; Vector2 rotX = rotation.X, rotY = rotation.Y; float renX = renderSize.X, renY = renderSize.Y; Vector2.Multiply(ref rotX, renX, out x); Vector2.Multiply(ref rotY, renY, out y); // Get the color for this particle float redValue = redLife[unitAge]; float greenValue = greenLife[unitAge]; float blueValue = blueLife[unitAge]; float visibilityValue = visibilityLife[unitAge] * visibilityScale[unitAge]; Color color = new Color((byte)(redValue * 255.0f), (byte)(greenValue * 255.0f), (byte)(blueValue * 255.0f), (byte)(visibilityValue * 255.0f)); // Vertex #0. vertexScratch[vertexOffset++] = new GFXVertexFormat.PCTTBN(new Vector3(-x.X - y.X + center.X, -x.Y - y.Y + center.Y, 0.0f), color, textureCoords[0], new Vector2(0.0f, 0.0f), tangent, normal); // Vertex #1. vertexScratch[vertexOffset++] = new GFXVertexFormat.PCTTBN(new Vector3(x.X - y.X + center.X, x.Y - y.Y + center.Y, 0.0f), color, textureCoords[1], new Vector2(0.0f, 0.0f), tangent, normal); // Vertex #2. vertexScratch[vertexOffset++] = new GFXVertexFormat.PCTTBN(new Vector3(x.X + y.X + center.X, x.Y + y.Y + center.Y, 0.0f), color, textureCoords[2], new Vector2(0.0f, 0.0f), tangent, normal); // Vertex #3. vertexScratch[vertexOffset++] = new GFXVertexFormat.PCTTBN(new Vector3(y.X - x.X + center.X, y.Y - x.Y + center.Y, 0.0f), color, textureCoords[3], new Vector2(0.0f, 0.0f), tangent, normal); // Set to next index. currentIndex = CurrentEmitterData.FirstInFrontOrder ? particleManagerPool[currentIndex].Previous : particleManagerPool[currentIndex].Next; } }
/// <summary> /// Copy the vertex data into an array. /// </summary> /// <param name="vb">The vertex array receiving the vertex data.</param> /// <param name="vbStart">The start index.</param> /// <param name="mat">The transform matrix to rotate vertex data with.</param> public void CopyVB(GFXVertexFormat.PCTTBN[] vb, int vbStart, Matrix mat) { _ComputeTangents(); for (int i = 0, idx = vbStart; i < _verts.Length; ++i) { Vector3 tang = new Vector3(_tangents[i].X, _tangents[i].Y, _tangents[i].Z); Vector3 binormal = Vector3.Cross(_norms[i], tang) * _tangents[i].W; tang = Vector3.TransformNormal(tang, mat); binormal = Vector3.TransformNormal(binormal, mat); Vector3 vert = Vector3.Transform(_verts[i], mat); Vector3 norm = Vector3.TransformNormal(_norms[i], mat); vb[idx++] = new GFXVertexFormat.PCTTBN( new Vector3(vert.X, vert.Y, vert.Z), (_colors != null) ? _colors[i] : Color.White, _tverts[i], (_tverts2 != null) ? _tverts2[i] : _tverts[i], new Vector4(tang.X, tang.Y, tang.Z, _tangents[i].W), new Vector4(norm.X, norm.Y, norm.Z, 0.0f)); } }