/// <summary>
        /// numberOfBuffers is the amount of vertex buffers used by the particle system for multi buffering.
        /// Multi buffering can avoid stalling of the GPU but will also increases it's memory consumption.
        /// If you want to avoid stalling create the same amount of buffers as your maximum rendered emitters at the
        /// same time.
        /// For example allocating one buffer with 16383 particles takes up 2048KB(2MB) GPU memory.
        /// This call requires that there is a GL context
        /// </summary>
        /// <param name="numberOfBuffers">the amount of vertex buffers used by the particle system for multi buffering.</param>
        /// <param name="maxParticlesPerBuffer">Maximum number of particles that you will be able to display.</param>
        public static void Init(int numberOfBuffers = 2, int maxParticlesPerBuffer = MaxPossibleParticles)
        {
            _numberOfVertexBuffers = numberOfBuffers;
            if (maxParticlesPerBuffer > MaxPossibleParticles)
            {
                maxParticlesPerBuffer = MaxPossibleParticles;
                Debug.WriteLine("StardustStarlingRenderer WARNING: Tried to render than possible particles, setting value to max");
            }
            _maxParticles = maxParticlesPerBuffer;
            SparrowParticleBuffers.CreateBuffers(maxParticlesPerBuffer, numberOfBuffers);

            if (!_initCalled)
            {
                for (int i = 0; i < 0x800; ++i)
                {
                    SCosLut[i & 0x7FF] = (float)Math.Cos(i * 0.00306796157577128245943617517898); // 0.003067 = 2PI/2048
                    SSinLut[i & 0x7FF] = (float)Math.Sin(i * 0.00306796157577128245943617517898);
                }
                // handle a lost device context
                SparrowSharp.ContextCreated += SparrowSharpOnContextCreated;
                _initCalled = true;
            }
        }
 private static void SparrowSharpOnContextCreated()
 {
     SparrowParticleBuffers.CreateBuffers(_maxParticles, _numberOfVertexBuffers);
 }
        private void RenderCustom(Painter painter, int mNumBatchedParticles, float parentAlpha)
        {
            if (_mNumParticles == 0 || SparrowParticleBuffers.BuffersCreated == false)
            {
                return;
            }
            if (mNumBatchedParticles > _maxParticles)
            {
                Debug.WriteLine("Over " + _maxParticles + " particles! Aborting rendering");
                return;
            }
            SparrowParticleBuffers.SwitchVertexBuffer();

            painter.FinishMeshBatch();
            painter.DrawCount += 1;
            painter.PrepareToDraw();

            global::Sparrow.Display.BlendMode.Get(BlendMode).Activate();

            RenderAlpha[0] = RenderAlpha[1] = RenderAlpha[2] = PremultiplyAlpha ? parentAlpha : 1;
            RenderAlpha[3] = parentAlpha;

            var program = ParticleProgram.GetProgram();

            program.Activate();

            int uAlpha = program.Uniforms["uAlpha"];

            Gl.Uniform4(uAlpha, RenderAlpha[0], RenderAlpha[1], RenderAlpha[2], RenderAlpha[3]);

            int uMvpMatrix = program.Uniforms["uMvpMatrix"];

            Gl.UniformMatrix4(uMvpMatrix, false, painter.State.MvpMatrix3D.RawData);

            //context.setTextureAt(0, mTexture.Base);

            Gl.BindBuffer(BufferTarget.ArrayBuffer, SparrowParticleBuffers.VertexBuffer);
            Gl.BufferData(BufferTarget.ArrayBuffer, (uint)(_vertexes.Length * sizeof(float)), _vertexes, BufferUsage.DynamicDraw);

            uint attribPosition = (uint)program.Attributes["aPosition"];

            Gl.EnableVertexAttribArray(attribPosition);
            Gl.VertexAttribPointer(attribPosition, 2, VertexAttribType.Float, false, 32, (IntPtr)0);

            uint attribColor = (uint)program.Attributes["aColor"];

            Gl.EnableVertexAttribArray(attribColor);
            Gl.VertexAttribPointer(attribColor, 4, VertexAttribType.Float, false, 32, (IntPtr)8);

            uint aTexCoords = (uint)program.Attributes["aTexCoords"];

            Gl.EnableVertexAttribArray(aTexCoords);
            Gl.VertexAttribPointer(aTexCoords, 2, VertexAttribType.Float, false, 32, (IntPtr)24);
            Gl.ActiveTexture(TextureUnit.Texture0);
            RenderUtil.SetSamplerStateAt(_mTexture.Base, _mTexture.NumMipMaps > 0, TexSmoothing);

            Gl.BindBuffer(BufferTarget.ElementArrayBuffer, SparrowParticleBuffers.IndexBuffer);

            // TODO limit max number of particles
            Gl.DrawElements(PrimitiveType.Triangles, (_mNumParticles + mNumBatchedParticles) * 6, DrawElementsType.UnsignedShort, IntPtr.Zero);

            Gl.DisableVertexAttribArray(attribPosition);
            Gl.DisableVertexAttribArray(attribColor);
            Gl.DisableVertexAttribArray(aTexCoords);
            Gl.BindTexture(TextureTarget.Texture2d, 0);
        }