public async Task RenderFrame()
        {
            await _context.ClearColorAsync(0, 0, 0, 1);

            await _context.ClearAsync(BufferBits.COLOR_BUFFER_BIT);


            Buffer.BlockCopy(spriteEngine.vertices, 0, byteArr, 0, byteArr.Length);
            await _context.BufferDataAsync(BufferType.ARRAY_BUFFER, byteArr, BufferUsageHint.DYNAMIC_DRAW);

            // this matrix will convert from pixels to clip space
            Matrix4x4 myMatrix = Matrix4x4.CreateOrthographic(_canvasReference.Width, _canvasReference.Height, 1, -1);

            // this matrix will translate our quad to dstX, dstY
            Matrix4x4 transMatrix = Matrix4x4.CreateTranslation(transVector);

            myMatrix = Matrix4x4.Multiply(myMatrix, transMatrix);

            // Set the matrix.
            await _context.UniformMatrixAsync(u_matrix_location, false, new float[16] {
                myMatrix.M11, myMatrix.M12, myMatrix.M13, myMatrix.M14, myMatrix.M21, myMatrix.M22, myMatrix.M23, myMatrix.M24, myMatrix.M31, myMatrix.M32, myMatrix.M33, myMatrix.M34, myMatrix.M41, myMatrix.M42, myMatrix.M43, myMatrix.M44
            });

            await _context.DrawArraysAsync(Primitive.TRIANGLES, 0, 6 *spriteEngine.spriteCount);


            spriteEngine.spriteCount = 0;
        }
        public static async Task DrawObject(WebGLContext gl, StoryboardObject obj)
        {
            if (!textureResourceMap.TryGetValue(obj.ImageFilePath, out var textureResource))
            {
                return;
            }

            ChangeAdditiveStatus(gl, obj.IsAdditive);

            var is_xflip = Math.Sign(obj.Scale.X);
            var is_yflip = Math.Sign(obj.Scale.Y);

            //adjust scale transform which value is negative
            var   horizon_flip  = obj.IsHorizonFlip | (is_xflip < 0);
            var   vertical_flip = obj.IsHorizonFlip | (is_yflip < 0);
            float scalex        = is_xflip * obj.Scale.X * textureResource.Size.Width;
            float scaley        = is_yflip * obj.Scale.Y * textureResource.Size.Height;

            await shader.UpdateColor(gl, obj.Color.X, obj.Color.Y, obj.Color.Z, obj.Color.W);

            await shader.UpdateFlip(gl, horizon_flip? -1 : 1, vertical_flip? -1 : 1);

            //anchor
            await shader.UpdateAnchor(gl, obj.OriginOffset.X, obj.OriginOffset.Y);

            //Create ModelMatrix
            Matrix3 model = Matrix3.Zero;
            float   cosa  = (float)Math.Cos(obj.Rotate);
            float   sina  = (float)Math.Sin(obj.Rotate);

            model.Row0.X = cosa * scalex;
            model.Row0.Y = -sina * scalex;
            model.Row1.X = sina * scaley;
            model.Row1.Y = cosa * scaley;

            model.Row2.X = obj.Postion.X - SB_WIDTH / 2f;
            model.Row2.Y = -obj.Postion.Y + SB_HEIGHT / 2f;

            unsafe
            {
                fixed(float *ptr = &martrix3Buffer[0])
                {
                    Unsafe.CopyBlock(ptr, &model.Row0.X, 9 * sizeof(float));
                }
            }

            await shader.UpdateModel(gl, false, martrix3Buffer);

            await shader.UpdateTexture(gl, textureResource.Texture);

            await gl.DrawArraysAsync(Primitive.TRIANGLE_FAN, 0, 4);
        }
        public async Task DrawAsync(ShaderProgram shaderProgram)
        {
            //TODO: add attribute dictionary to the shader program
            await _positions.BindToAttributeAsync((uint)shaderProgram.Attributes.GetValueOrDefault("position"));

            await _normals.BindToAttributeAsync((uint)shaderProgram.Attributes.GetValueOrDefault("normal"));

            await _uvs.BindToAttributeAsync((uint)shaderProgram.Attributes.GetValueOrDefault("uv"));

            await _gl.UniformMatrixAsync(shaderProgram.Uniforms.GetValueOrDefault("model"), false, _position);

            await _texture.UseAsync(shaderProgram.Uniforms.GetValueOrDefault("diffuse"), 0);

            await _gl.DrawArraysAsync(Primitive.TRIANGLES, 0, _vertexCount);
        }