/// <summary>
 /// configures vertex color to the vertex component data using the sprite object.
 /// </summary>
 /// <param name="vertexData">target vertex component data</param>
 /// <param name="obj">source sprite object</param>
 /// <param name="startIndex">start index of the vertex component data</param>
 private static void SetBufferColor(ref VertexPositionColorTexture[] vertexData,
                                    PointSpriteObject obj, int startIndex)
 {
     for (int i = 0; i < 4; i++)
     {
         vertexData[startIndex + i].Color = obj.Color;
     }
 }
        /// <summary>
        /// gets a right down position of each sprite object.
        /// </summary>
        /// <param name="index">an index of sprite object</param>
        /// <param name="vec">out vector</param>
        public void GetRightBottom(int index, ref Vector3 vec)
        {
            if (pointSpriteList.Count <= index || 0 > index)
            {
                throw new ArgumentException("Invalid index.");
            }

            PointSpriteObject obj = pointSpriteList[index];

            vec.X = obj.Center.X + (obj.Width * 0.5f);
            vec.Y = obj.Center.Y + (obj.Height * 0.5f);
            vec.Z = obj.Center.Z;
        }
        /// <summary>
        /// configures texture coordinates to the vertex component data
        /// using the sprite object.
        /// </summary>
        /// <param name="vertexData">target vertex component data</param>
        /// <param name="obj">source sprite object</param>
        /// <param name="startIndex">start index of the vertex component data</param>
        /// <param name="space">3D render space</param>
        private static void SetBufferTextureCoord(
            ref VertexPositionColorTexture[] vertexData, PointSpriteObject obj,
            int startIndex, RenderingSpace space)
        {
            float u1 = 0.0f, v1 = 0.0f, u2 = 0.0f, v2 = 0.0f;

            // Differ Y axis of the 3D and 2D
            bool flipY = (space == RenderingSpace.Screen ? !obj.FlipY : obj.FlipY);

            if (obj.FlipX)
            {
                if (flipY)
                {
                    u1 = obj.MaxUV.X;
                    v1 = obj.MaxUV.Y;
                    u2 = obj.MinUV.X;
                    v2 = obj.MinUV.Y;
                }
                else
                {
                    u1 = obj.MaxUV.X;
                    v1 = obj.MinUV.Y;
                    u2 = obj.MinUV.X;
                    v2 = obj.MaxUV.Y;
                }
            }
            else
            {
                if (flipY)
                {
                    u1 = obj.MinUV.X;
                    v1 = obj.MaxUV.Y;
                    u2 = obj.MaxUV.X;
                    v2 = obj.MinUV.Y;
                }
                else
                {
                    u1 = obj.MinUV.X;
                    v1 = obj.MinUV.Y;
                    u2 = obj.MaxUV.X;
                    v2 = obj.MaxUV.Y;
                }
            }

            vertexData[startIndex + 0].TextureCoordinate = new Vector2(u1, v1);
            vertexData[startIndex + 1].TextureCoordinate = new Vector2(u2, v1);
            vertexData[startIndex + 2].TextureCoordinate = new Vector2(u2, v2);
            vertexData[startIndex + 3].TextureCoordinate = new Vector2(u1, v2);
        }
        /// <summary>
        /// configures a transformed matrix to the vertex component data
        /// using the sprite object.
        /// </summary>
        /// <param name="vertexData">target vertex component data</param>
        /// <param name="obj">source sprite object</param>
        /// <param name="startIndex">start index of the vertex component data</param>
        /// <param name="transformMatrix">transformed matrix</param>
        /// <param name="space">3D render space</param>
        private static void SetBufferPosition(
            ref VertexPositionColorTexture[] vertexData, PointSpriteObject obj,
            int startIndex, Matrix transformMatrix, RenderingSpace space)
        {
            float cx = obj.Width * 0.5f;
            float cy = obj.Height * 0.5f;

            switch (obj.Rotation)
            {
            case PointSpriteObject.RotationAngle.Angle0:
            {
                vertexData[startIndex + 0].Position =
                    new Vector3(-cx, -cy, 0.0f);
                vertexData[startIndex + 1].Position =
                    new Vector3(+cx, -cy, 0.0f);
                vertexData[startIndex + 2].Position =
                    new Vector3(+cx, +cy, 0.0f);
                vertexData[startIndex + 3].Position =
                    new Vector3(-cx, +cy, 0.0f);
            }
            break;

            case PointSpriteObject.RotationAngle.Angle90:
            {
                vertexData[startIndex + 0].Position =
                    new Vector3(+cx, -cy, 0.0f);
                vertexData[startIndex + 1].Position =
                    new Vector3(+cx, +cy, 0.0f);
                vertexData[startIndex + 2].Position =
                    new Vector3(-cx, +cy, 0.0f);
                vertexData[startIndex + 3].Position =
                    new Vector3(-cx, -cy, 0.0f);
            }
            break;

            case PointSpriteObject.RotationAngle.Angle180:
            {
                vertexData[startIndex + 0].Position =
                    new Vector3(+cx, +cy, 0.0f);
                vertexData[startIndex + 1].Position =
                    new Vector3(-cx, +cy, 0.0f);
                vertexData[startIndex + 2].Position =
                    new Vector3(-cx, -cy, 0.0f);
                vertexData[startIndex + 3].Position =
                    new Vector3(+cx, -cy, 0.0f);
            }
            break;

            case PointSpriteObject.RotationAngle.Angle270:
            {
                vertexData[startIndex + 0].Position =
                    new Vector3(-cx, +cy, 0.0f);
                vertexData[startIndex + 1].Position =
                    new Vector3(-cx, -cy, 0.0f);
                vertexData[startIndex + 2].Position =
                    new Vector3(+cx, -cy, 0.0f);
                vertexData[startIndex + 3].Position =
                    new Vector3(+cx, +cy, 0.0f);
            }
            break;
            }

            for (int i = 0; i < 4; i++)
            {
                int arrayIndex = startIndex + i;

                Vector3.TransformNormal(ref vertexData[arrayIndex].Position,
                                        ref transformMatrix,
                                        out vertexData[arrayIndex].Position);

                vertexData[arrayIndex].Position += obj.Center;

                if (space == RenderingSpace.Screen)
                {
                    vertexData[arrayIndex].Position =
                        HelperMath.Make2DCoord(vertexData[arrayIndex].Position);
                }
            }
        }
        /// <summary>
        /// updates the vertex data and draws
        /// </summary>
        /// <param name="renderTracer">render information</param>
        protected override void OnDraw(RenderTracer renderTracer)
        {
            int objectCount = 0;

            for (int i = 0; i < this.count; i++)
            {
                if (pointSpriteList[i].Enable == false)
                {
                    continue;
                }
                objectCount++;
            }

            if (objectCount == 0)
            {
                return;
            }

            PrimitiveCount    = objectCount * 2;
            UpdateVertexCount = this.count * vertexStride;

            this.alwaysUpdate = true;

            //  needs to update?
            if (renderTracer.View != lastViewMatrix)
            {
                needToUpdate        = true;
                this.lastViewMatrix = renderTracer.View;
            }

            if (this.alwaysUpdate || needToUpdate)
            {
                int vertexOffset = 0;
                int indexOffset  = 0;

                // calculates inverse view matrix.
                Matrix transformMatrix =
                    Helper3D.Transpose(this.TransformedMatrix * renderTracer.View);

                for (int i = 0; i < this.count; i++)
                {
                    PointSpriteObject obj = pointSpriteList[i];

                    if (obj.Enable == false)
                    {
                        continue;
                    }

                    //  updates vertex positions.
                    SetBufferPosition(ref vertexData, obj, vertexOffset,
                                      transformMatrix, this.space);

                    //  updates texture coordinates.
                    SetBufferTextureCoord(ref vertexData, obj,
                                          vertexOffset, this.space);

                    //  updates vertex colors.
                    SetBufferColor(ref vertexData, obj, vertexOffset);

                    indexData[indexOffset + 0] = (short)(vertexOffset + 0);
                    indexData[indexOffset + 1] = (short)(vertexOffset + 1);
                    indexData[indexOffset + 2] = (short)(vertexOffset + 2);
                    indexData[indexOffset + 3] = (short)(vertexOffset + 3);
                    indexData[indexOffset + 4] = (short)(vertexOffset + 0);
                    indexData[indexOffset + 5] = (short)(vertexOffset + 2);

                    vertexOffset += vertexStride;
                    indexOffset  += indexStride;
                }

                if (userPrimitive == false)
                {
                    //  binds the vertex buffer.
                    BindVertexBuffer();

                    //  binds the index buffer.
                    BindIndexBuffer();
                }

                if (needToUpdate)
                {
                    needToUpdate = false;
                }
            }

            // draws mesh
            base.OnDraw(renderTracer);
        }