using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using GraphiXNA.Materials;

namespace GraphiXNA.Graphics.Library
{
    public class Sphere : Object3D
    {
        float Radius = 5;
        int Rings = 5;
        int Segments = 20;

        public Sphere(GraphicsDevice graphicsDevice, float radius, int rings, int segments)
            : base(graphicsDevice)
        {
            Radius = radius;
            Rings = rings;
            Segments = segments;

            NumberOfVertices = (rings + 1) * (segments + 1);
            NumberOfIndices = 2 * rings * (segments + 1);
            PrimitiveCount = NumberOfIndices - 2;
            PrimitiveType = PrimitiveType.TriangleStrip;
            VertexStride = VertexPositionNormalTexture.SizeInBytes;

            LoadContent();
        }

        private void LoadContent()
        {
            VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[NumberOfVertices];
            short[] indices = new short[NumberOfIndices];


            // Establish constants used in sphere generation
            float fDeltaRingAngle = ((float)Math.PI / Rings);
            float fDeltaSegAngle = (2.0f * (float)Math.PI / Segments);

            int vertexPos = 0;
            int indexPos = 0;
            short verticeIndex = 0;
            float r0;
            float y0;
            float x0;
            float z0;

            // Generate the group of rings for the sphere
            for (int ring = 0; ring < Rings + 1; ring++)
            {
                r0 = (float)Math.Sin(ring * fDeltaRingAngle);
                y0 = (float)Math.Cos(ring * fDeltaRingAngle);

                // Generate the group of segments for the current ring
                for (int seg = 0; seg < Segments + 1; seg++)
                {
                    x0 = r0 * (float)Math.Sin(seg * fDeltaSegAngle);
                    z0 = r0 * (float)Math.Cos(seg * fDeltaSegAngle);

                    // Add one vertices to the strip which makes up the sphere
                    vertices[vertexPos].Position = new Vector3(x0 * Radius, y0 * Radius, z0 * Radius); // normalized 
                    vertices[vertexPos].Normal = vertices[vertexPos].Position;
                    vertices[vertexPos].TextureCoordinate.X = -(float)seg / (float)Segments;
                    vertices[vertexPos].TextureCoordinate.Y = (float)ring / (float)Rings;

                    vertexPos++;

                    // add two indices except for last ring 
                    if (ring != Rings)
                    {
                        indices[indexPos] = verticeIndex;
                        indices[indexPos + 1] = (short)(verticeIndex + (Segments + 1));
                        verticeIndex++;
                        indexPos += 2;
                    }
                } // end for seg 
            } // end for ring 

            VertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionNormalTexture.SizeInBytes * NumberOfVertices, BufferUsage.WriteOnly);
            IndexBuffer = new IndexBuffer(GraphicsDevice, 2 * NumberOfIndices, BufferUsage.WriteOnly, IndexElementSize.SixteenBits);

            VertexBuffer.SetData<VertexPositionNormalTexture>(vertices);
            IndexBuffer.SetData<short>(indices);

            VertexDeclaration = new VertexDeclaration(GraphicsDevice, VertexPositionNormalTexture.VertexElements);
        }
    }
}
