/// <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));
            }
        }