/// <summary>
        /// draws the particles on a GPU system
        /// </summary>
        protected override void DrawGpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Texture2D positionTex, Texture2D velocityRotation, Texture2D colourTex, Texture2D userValues, bool usesUserValuesPositionBuffer)
        {
            //this is very similar to the billboard drawer (see it for reference)
            Vector2 targetSize = state.DrawTarget.Size;

            state.PushRenderState();
            state.RenderState.AlphaBlend = blendMode;
            state.RenderState.DepthColourCull.DepthWriteEnabled = false;

            Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state);

            //get the shared vertice
            BillboardParticles2DElement.GenerateBillboardVertices(state, ref vertices, ref indices);

            int count = (int)particleCount;

            DrawVelocityParticles_GpuTex       shaderNoColour = null;
            DrawVelocityParticlesColour_GpuTex shaderColour   = null;
            //user variants
            DrawVelocityParticles_GpuTex_UserOffset       shaderNoColour_UO = null;
            DrawVelocityParticlesColour_GpuTex_UserOffset shaderColour_UO   = null;

            float resolutionXF = (float)positionTex.Width;
            float resolutionYF = (float)positionTex.Height;

            Vector2 invTextureSize;

            Vector2 velScale = new Vector2(velocityScale, 0);

            if (this.useRotationToScaleVelocityEffect)
            {
                velScale = new Vector2(0, velocityScale);
            }
            invTextureSize = new Vector2(1.0f / resolutionXF, 1.0f / resolutionYF);


            IShader shader;

            if (!usesUserValuesPositionBuffer)
            {
                if (colourTex != null)
                {
                    shader = shaderColour = state.GetShader <DrawVelocityParticlesColour_GpuTex>();

                    shaderColour.PositionTexture = positionTex;
                    shaderColour.ColourTexture   = colourTex;
                    shaderColour.VelocityTexture = velocityRotation;
                    shaderColour.DisplayTexture  = displayTexture;

                    shaderColour.SetVelocityScale(ref velScale);
                }
                else
                {
                    shader = shaderNoColour = state.GetShader <DrawVelocityParticles_GpuTex>();

                    shaderNoColour.PositionTexture = positionTex;
                    shaderNoColour.VelocityTexture = velocityRotation;
                    shaderNoColour.DisplayTexture  = displayTexture;

                    shaderNoColour.SetVelocityScale(ref velScale);
                }
            }
            else
            {
                if (colourTex != null)
                {
                    shader = shaderColour_UO = state.GetShader <DrawVelocityParticlesColour_GpuTex_UserOffset>();

                    shaderColour_UO.PositionTexture = positionTex;
                    shaderColour_UO.ColourTexture   = colourTex;
                    shaderColour_UO.VelocityTexture = velocityRotation;
                    shaderColour_UO.UserTexture     = userValues;
                    shaderColour_UO.DisplayTexture  = displayTexture;

                    shaderColour_UO.SetVelocityScale(ref velScale);
                }
                else
                {
                    shader = shaderNoColour_UO = state.GetShader <DrawVelocityParticles_GpuTex_UserOffset>();

                    shaderNoColour_UO.PositionTexture = positionTex;
                    shaderNoColour_UO.VelocityTexture = velocityRotation;
                    shaderNoColour_UO.UserTexture     = userValues;
                    shaderNoColour_UO.DisplayTexture  = displayTexture;

                    shaderNoColour_UO.SetVelocityScale(ref velScale);
                }
            }


            int drawn = 0;

            while (count > 0)
            {
                int drawCount = Math.Min(count, vertices.Count / 4);

                if (!usesUserValuesPositionBuffer)
                {
                    if (colourTex != null)
                    {
                        shaderColour.TextureSizeOffset = new Vector3(invTextureSize, (float)drawn);
                    }
                    else
                    {
                        shaderNoColour.TextureSizeOffset = new Vector3(invTextureSize, (float)drawn);
                    }
                }
                else
                {
                    if (colourTex != null)
                    {
                        shaderColour_UO.TextureSizeOffset = new Vector3(invTextureSize, (float)drawn);
                    }
                    else
                    {
                        shaderNoColour_UO.TextureSizeOffset = new Vector3(invTextureSize, (float)drawn);
                    }
                }

                //bind
                shader.Bind(state);

                vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0);

                count -= drawCount;
                drawn += drawCount;
            }


            state.PopRenderState();
        }
        /// <summary>
        /// implements the method to draw gpu particles
        /// </summary>
        protected override void DrawGpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Texture2D positionTex, Texture2D velocityRotation, Texture2D colourTex, Texture2D userValues, bool usesUserValuesPositionBuffer)
        {
            Vector2 targetSize = state.DrawTarget.Size;

            state.PushRenderState();
            state.RenderState.AlphaBlend = blendMode;
            state.RenderState.DepthColourCull.DepthWriteEnabled = false;

            //get the display texture, or a white texture if none exists
            Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state);

            //get / create the shared vertices and indices for drawing billboard particles
            BillboardParticles2DElement.GenerateBillboardVertices(state, ref vertices, ref indices);

            int count = (int)particleCount;

            //instances of the two possible shaders
            DrawVelocityBillboardParticles_GpuTex3D       shaderNoColour = null;
            DrawVelocityBillboardParticlesColour_GpuTex3D shaderColour   = null;
            //user variantes
            DrawVelocityBillboardParticles_GpuTex3D_UserOffset       shaderNoColour_UO = null;
            DrawVelocityBillboardParticlesColour_GpuTex3D_UserOffset shaderColour_UO   = null;

            float resolutionXF = (float)positionTex.Width;
            float resolutionYF = (float)positionTex.Height;

            Vector2 invTextureSize = new Vector2(1.0f / resolutionXF, 1.0f / resolutionYF);

            Matrix cameraMatrix;

            state.Camera.GetCameraMatrix(out cameraMatrix);

            Vector3 worldSpaceYAxis = new Vector3(cameraMatrix.M21, cameraMatrix.M22, cameraMatrix.M23);


            Vector2 velScale = new Vector2(velocityScale, 0);

            if (this.useRotationToScaleVelocityEffect)
            {
                velScale = new Vector2(0, velocityScale);
            }

            IShader shader;

            if (!usesUserValuesPositionBuffer)
            {
                if (colourTex != null)                 // does this particle system use colours?
                {
                    //get the shader
                    shaderColour = state.GetShader <DrawVelocityBillboardParticlesColour_GpuTex3D>();

                    //set the samplers
                    shaderColour.PositionTexture = positionTex;
                    shaderColour.ColourTexture   = colourTex;
                    shaderColour.VelocityTexture = velocityRotation;
                    shaderColour.DisplayTexture  = displayTexture;

                    shaderColour.SetWorldSpaceYAxis(ref worldSpaceYAxis);
                    shaderColour.SetVelocityScale(ref velScale);
                    shader = shaderColour;
                }
                else
                {
                    shaderNoColour = state.GetShader <DrawVelocityBillboardParticles_GpuTex3D>();

                    shaderNoColour.PositionTexture = positionTex;
                    shaderNoColour.VelocityTexture = velocityRotation;
                    shaderNoColour.DisplayTexture  = displayTexture;

                    shaderNoColour.SetWorldSpaceYAxis(ref worldSpaceYAxis);
                    shaderNoColour.SetVelocityScale(ref velScale);
                    shader = shaderNoColour;
                }
            }
            else
            {
                if (colourTex != null)                 // does this particle system use colours?
                {
                    //get the shader
                    shaderColour_UO = state.GetShader <DrawVelocityBillboardParticlesColour_GpuTex3D_UserOffset>();

                    //set the samplers
                    shaderColour_UO.PositionTexture = positionTex;
                    shaderColour_UO.ColourTexture   = colourTex;
                    shaderColour_UO.VelocityTexture = velocityRotation;
                    shaderColour_UO.UserTexture     = userValues;
                    shaderColour_UO.DisplayTexture  = displayTexture;

                    shaderColour_UO.SetWorldSpaceYAxis(ref worldSpaceYAxis);
                    shaderColour_UO.SetVelocityScale(ref velScale);
                    shader = shaderColour_UO;
                }
                else
                {
                    shaderNoColour_UO = state.GetShader <DrawVelocityBillboardParticles_GpuTex3D_UserOffset>();

                    shaderNoColour_UO.PositionTexture = positionTex;
                    shaderNoColour_UO.VelocityTexture = velocityRotation;
                    shaderNoColour_UO.UserTexture     = userValues;
                    shaderNoColour_UO.DisplayTexture  = displayTexture;

                    shaderNoColour_UO.SetWorldSpaceYAxis(ref worldSpaceYAxis);
                    shaderNoColour_UO.SetVelocityScale(ref velScale);
                    shader = shaderNoColour_UO;
                }
            }


            int drawn = 0;

            while (count > 0)
            {
                //draw upto vertices.Count / 4 (4 vertices per quad)
                int drawCount = Math.Min(count, vertices.Count / 4);

                //set the inverse texture size, and the start offset value, then bind the shader
                if (!usesUserValuesPositionBuffer)
                {
                    if (colourTex != null)
                    {
                        shaderColour.InvTextureSizeOffset = new Vector3(invTextureSize, (float)drawn);
                    }
                    else
                    {
                        shaderNoColour.InvTextureSizeOffset = new Vector3(invTextureSize, (float)drawn);
                    }
                }
                else
                {
                    if (colourTex != null)
                    {
                        shaderColour_UO.InvTextureSizeOffset = new Vector3(invTextureSize, (float)drawn);
                    }
                    else
                    {
                        shaderNoColour_UO.InvTextureSizeOffset = new Vector3(invTextureSize, (float)drawn);
                    }
                }

                //bind
                shader.Bind(state);

                //draw!
                vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0);

                count -= drawCount;
                drawn += drawCount;
            }

            //and done.
            state.PopRenderState();
        }
        //draws on CPU particle systems
        /// <summary>
        /// draws the particles from a CPU system
        /// </summary>
        protected override void DrawCpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Vector4[] positionSize, Vector4[] velocityRotation, Vector4[] colourData, Vector4[] userValues)
        {
            //this is very similar to the billboard drawer (see it for reference)
            Vector2 targetSize = state.DrawTarget.Size;

            state.PushRenderState();
            state.RenderState.AlphaBlend = blendMode;
            state.RenderState.DepthColourCull.DepthWriteEnabled = false;

            Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state);

            BillboardParticles2DElement.GenerateBillboardVertices(state, ref this.vertices, ref this.indices);


            int count = (int)particleCount;



            DrawVelocityParticles_BillboardCpu       shaderNoColour = null;
            DrawVelocityParticlesColour_BillboardCpu shaderColour   = null;


            if (colourData != null)
            {
                shaderColour = state.GetShader <DrawVelocityParticlesColour_BillboardCpu>();
            }
            else
            {
                shaderNoColour = state.GetShader <DrawVelocityParticles_BillboardCpu>();
            }

            Vector2 velScale = new Vector2(velocityScale, 0);

            if (this.useRotationToScaleVelocityEffect)
            {
                velScale = new Vector2(0, velocityScale);
            }

            int drawn = 0;

            while (count > 0)
            {
                int drawCount;

                drawCount = Math.Min(count, 80);

                if (colourData != null)
                {
                    shaderColour.PositionData.SetArray(positionSize, drawn);
                    shaderColour.VelocityData.SetArray(velocityRotation, drawn);
                    shaderColour.ColourData.SetArray(colourData, drawn);

                    shaderColour.DisplayTexture = displayTexture;
                    shaderColour.SetVelocityScale(ref velScale);

                    shaderColour.Bind(state);
                }
                else
                {
                    shaderNoColour.PositionData.SetArray(positionSize, drawn);
                    shaderNoColour.VelocityData.SetArray(velocityRotation, drawn);

                    shaderNoColour.DisplayTexture = displayTexture;
                    shaderNoColour.SetVelocityScale(ref velScale);

                    shaderNoColour.Bind(state);
                }

                vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0);

                count -= drawCount;
                drawn += drawCount;
            }


            state.PopRenderState();
        }
        /// <summary>
        /// implements the method to draw cpu processed particles
        /// </summary>
        protected override void DrawCpuParticles(DrawState state, Content.ParticleSystemTypeData particleType, uint particleCount, AlphaBlendState blendMode, Vector4[] positionSize, Vector4[] velocityRotation, Vector4[] colourData, Vector4[] userValues)
        {
            //this is a bit more complex, but mostly the same as the GPU draw method
            Vector2 targetSize = state.DrawTarget.Size;

            state.PushRenderState();
            state.RenderState.AlphaBlend = blendMode;
            state.RenderState.DepthColourCull.DepthWriteEnabled = false;

            Texture2D displayTexture = particleType.Texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state);

            BillboardParticles2DElement.GenerateBillboardVertices(state, ref this.vertices, ref this.indices);

            Matrix cameraMatrix;

            state.Camera.GetCameraMatrix(out cameraMatrix);

            Vector3 worldSpaceYAxis = new Vector3(cameraMatrix.M21, cameraMatrix.M22, cameraMatrix.M23);


            Vector2 velScale = new Vector2(velocityScale, 0);

            if (this.useRotationToScaleVelocityEffect)
            {
                velScale = new Vector2(0, velocityScale);
            }



            int count = (int)particleCount;

            DrawVelocityBillboardParticles_BillboardCpu3D       shaderNoColour = null;
            DrawVelocityBillboardParticlesColour_BillboardCpu3D shaderColour   = null;

            if (colourData != null)
            {
                shaderColour = state.GetShader <DrawVelocityBillboardParticlesColour_BillboardCpu3D>();
                shaderColour.SetWorldSpaceYAxis(ref worldSpaceYAxis);
                shaderColour.SetVelocityScale(ref velScale);
            }
            else
            {
                shaderNoColour = state.GetShader <DrawVelocityBillboardParticles_BillboardCpu3D>();
                shaderNoColour.SetWorldSpaceYAxis(ref worldSpaceYAxis);
                shaderNoColour.SetVelocityScale(ref velScale);
            }

            int drawn = 0;

            while (count > 0)
            {
                int drawCount;

                drawCount = Math.Min(count, 75);

                if (colourData != null)
                {
                    shaderColour.PositionData.SetArray(positionSize, drawn);
                    shaderColour.VelocityData.SetArray(velocityRotation, drawn);
                    shaderColour.ColourData.SetArray(colourData, drawn);

                    shaderColour.DisplayTexture = displayTexture;

                    shaderColour.Bind(state);
                }
                else
                {
                    shaderNoColour.PositionData.SetArray(positionSize, drawn);
                    shaderNoColour.VelocityData.SetArray(velocityRotation, drawn);

                    shaderNoColour.DisplayTexture = displayTexture;

                    shaderNoColour.Bind(state);
                }

                vertices.Draw(state, indices, PrimitiveType.TriangleList, drawCount * 2, 0, 0);

                count -= drawCount;
                drawn += drawCount;
            }


            state.PopRenderState();
        }