public static BasicGeometry CreateSphere <T>(GraphicsDevice device, int slices, int stacks,
                                                     float sliceAngle1, float sliceAngle2, float stackAngle1, float stackAngle2,
                                                     Func <VertexPositionNormalTexture, T> createVertexCallback, bool insideVisible) where T : struct
        {
            if (slices < 3 || stacks < 3 || slices > ushort.MaxValue || stacks > ushort.MaxValue || (slices + 1) * (stacks + 1) > ushort.MaxValue)
            {
                throw new ArgumentOutOfRangeException("Sphere does not support 64K+ vertices");
            }
            if (sliceAngle1 > sliceAngle2 || stackAngle1 >= stackAngle2)
            {
                throw new ArgumentOutOfRangeException("Angles are wrong");
            }
            var   vpnt = new T[(slices + 1) * (stacks + 1)];
            float phi, theta;
            float dphi = (stackAngle2 - stackAngle1) / stacks;
            float dtheta = sliceAngle2 == sliceAngle1 ? MathHelper.TwoPi / slices : (sliceAngle2 - sliceAngle1) / slices;
            float x, y, z, sc;
            int   index = 0;

            for (int stack = 0; stack <= stacks; stack++)
            {
                phi = stack == stacks ? stackAngle2 : stackAngle1 + stack * dphi;
                y   = (float)Math.Sin(phi);
                sc  = -(float)Math.Cos(phi);
                for (int slice = 0; slice <= slices; slice++)
                {
                    theta         = slice == slices ? sliceAngle2 : sliceAngle1 + slice * dtheta;
                    x             = sc * (float)Math.Sin(theta);
                    z             = sc * (float)Math.Cos(theta);
                    vpnt[index++] = createVertexCallback(new VertexPositionNormalTexture(new Vector3(x, y, z), new Vector3(x, y, z),
                                                                                         new Vector2((float)slice / (float)slices, (float)stack / (float)stacks)));
                }
            }
            var indices = new ushort[slices * stacks * 6];

            index = 0;
            int k = slices + 1;

            for (int stack = 0; stack < stacks; stack++)
            {
                for (int slice = 0; slice < slices; slice++)
                {
                    indices[index++] = (ushort)((stack + 0) * k + slice);
                    indices[index++] = insideVisible ? (ushort)((stack + 0) * k + slice + 1) : (ushort)((stack + 1) * k + slice + 0);
                    indices[index++] = insideVisible ? (ushort)((stack + 1) * k + slice + 0) : (ushort)((stack + 0) * k + slice + 1);
                    indices[index++] = (ushort)((stack + 0) * k + slice + 1);
                    indices[index++] = insideVisible ? (ushort)((stack + 1) * k + slice + 1) : (ushort)((stack + 1) * k + slice);
                    indices[index++] = insideVisible ? (ushort)((stack + 1) * k + slice) : (ushort)((stack + 1) * k + slice + 1);
                }
            }

            var ret = new BasicGeometry( );

            ret.VertexBuffer = new VertexBuffer(device, typeof(T), vpnt.Length, BufferUsage.WriteOnly);
            ret.VertexBuffer.SetData(vpnt);
            ret.IndexBuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly);
            ret.IndexBuffer.SetData(indices);
            ret.Effect = new BasicEffect(device);
            return(ret);
        }
        public static BasicGeometry CreateCube <T>(GraphicsDevice device,
                                                   Func <VertexPositionNormalTexture, T> createVertexCallback, bool insideVisible) where T : struct
        {
            var vertices = new VertexPositionNormalTexture[] {
                // X face
                new VertexPositionNormalTexture(new Vector3(1, -1, 1), new Vector3(1, 0, 0), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(1, 1, 1), new Vector3(1, 0, 0), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(1, -1, -1), new Vector3(1, 0, 0), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(1, 1, -1), new Vector3(1, 0, 0), new Vector2(1, 1)),
                // -X face
                new VertexPositionNormalTexture(new Vector3(-1, -1, -1), new Vector3(-1, 0, 0), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(-1, 1, -1), new Vector3(-1, 0, 0), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(-1, -1, 1), new Vector3(-1, 0, 0), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(-1, 1, 1), new Vector3(-1, 0, 0), new Vector2(1, 1)),
                // Y face
                new VertexPositionNormalTexture(new Vector3(-1, 1, -1), new Vector3(0, 1, 0), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(1, 1, -1), new Vector3(0, 1, 0), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(-1, 1, 1), new Vector3(0, 1, 0), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(1, 1, 1), new Vector3(0, 1, 0), new Vector2(1, 1)),
                // -Y face
                new VertexPositionNormalTexture(new Vector3(-1, -1, -1), new Vector3(0, -1, 0), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(-1, -1, 1), new Vector3(0, -1, 0), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(1, -1, -1), new Vector3(0, -1, 0), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(1, -1, 1), new Vector3(0, -1, 0), new Vector2(1, 1)),
                // Z face
                new VertexPositionNormalTexture(new Vector3(-1, -1, 1), new Vector3(0, 0, 1), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(-1, 1, 1), new Vector3(0, 0, 1), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(1, -1, 1), new Vector3(0, 0, 1), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(1, 1, 1), new Vector3(0, 0, 1), new Vector2(1, 1)),
                // -Z face
                new VertexPositionNormalTexture(new Vector3(1, -1, -1), new Vector3(0, 0, -1), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(1, 1, -1), new Vector3(0, 0, -1), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(-1, -1, -1), new Vector3(0, 0, -1), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(-1, 1, -1), new Vector3(0, 0, -1), new Vector2(1, 1)),
            };
            var convertedVertices = Array.ConvertAll(vertices, x => createVertexCallback(x));
            var indices           = insideVisible ?
                                    new ushort[]
            {
                0, 2, 1, 1, 2, 3,
                4, 6, 5, 5, 6, 7,
                8, 10, 9, 9, 10, 11,
                12, 14, 13, 13, 14, 15,
                16, 18, 17, 17, 18, 19,
                20, 22, 21, 21, 22, 23
            } : new ushort[]
            {
                0, 1, 2, 2, 1, 3,
                4, 5, 6, 6, 5, 7,
                8, 9, 10, 10, 9, 11,
                12, 13, 14, 14, 13, 15,
                16, 17, 18, 18, 17, 19,
                20, 21, 22, 22, 21, 23
            };

            var ret = new BasicGeometry( );

            ret.VertexBuffer = new VertexBuffer(device, typeof(T), 24, BufferUsage.WriteOnly);
            ret.VertexBuffer.SetData(convertedVertices);
            ret.IndexBuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly);
            ret.IndexBuffer.SetData(indices);
            ret.Effect = new BasicEffect(device);
            ret.Effect.EnableDefaultLighting( );
            ret.Effect.PreferPerPixelLighting = true;
            ret.Effect.SpecularPower          = 500;
            ret.Effect.SpecularColor          = new Vector3(0.9f, 0.9f, 1);
            return(ret);
        }
        public static BasicGeometry CreateRoundedCube <T>(GraphicsDevice device,
                                                          Func <VertexPositionNormalTexture, T> createVertexCallback, float roundedPortion) where T : struct
        {
            float a        = roundedPortion;
            var   vertices = new VertexPositionNormalTexture[] {
                // X face: 0-3
                new VertexPositionNormalTexture(new Vector3(1, a - 1, 1 - a), new Vector3(1, 0, 0), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(1, 1 - a, 1 - a), new Vector3(1, 0, 0), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(1, a - 1, a - 1), new Vector3(1, 0, 0), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(1, 1 - a, a - 1), new Vector3(1, 0, 0), new Vector2(1, 1)),
                // -X face: 4-7
                new VertexPositionNormalTexture(new Vector3(-1, a - 1, a - 1), new Vector3(-1, 0, 0), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(-1, 1 - a, a - 1), new Vector3(-1, 0, 0), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(-1, a - 1, 1 - a), new Vector3(-1, 0, 0), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(-1, 1 - a, 1 - a), new Vector3(-1, 0, 0), new Vector2(1, 1)),
                // Y face: 8-11
                new VertexPositionNormalTexture(new Vector3(a - 1, 1, a - 1), new Vector3(0, 1, 0), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(1 - a, 1, a - 1), new Vector3(0, 1, 0), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(a - 1, 1, 1 - a), new Vector3(0, 1, 0), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(1 - a, 1, 1 - a), new Vector3(0, 1, 0), new Vector2(1, 1)),
                // -Y face: 12-15
                new VertexPositionNormalTexture(new Vector3(a - 1, -1, a - 1), new Vector3(0, -1, 0), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(a - 1, -1, 1 - a), new Vector3(0, -1, 0), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(1 - a, -1, a - 1), new Vector3(0, -1, 0), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(1 - a, -1, 1 - a), new Vector3(0, -1, 0), new Vector2(1, 1)),
                // Z face: 16-19
                new VertexPositionNormalTexture(new Vector3(a - 1, a - 1, 1), new Vector3(0, 0, 1), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(a - 1, 1 - a, 1), new Vector3(0, 0, 1), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(1 - a, a - 1, 1), new Vector3(0, 0, 1), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(1 - a, 1 - a, 1), new Vector3(0, 0, 1), new Vector2(1, 1)),
                // -Z face: 20-23
                new VertexPositionNormalTexture(new Vector3(1 - a, a - 1, -1), new Vector3(0, 0, -1), new Vector2(0, 0)),
                new VertexPositionNormalTexture(new Vector3(1 - a, 1 - a, -1), new Vector3(0, 0, -1), new Vector2(0, 1)),
                new VertexPositionNormalTexture(new Vector3(a - 1, a - 1, -1), new Vector3(0, 0, -1), new Vector2(1, 0)),
                new VertexPositionNormalTexture(new Vector3(a - 1, 1 - a, -1), new Vector3(0, 0, -1), new Vector2(1, 1)),
            };
            var convertedVertices = Array.ConvertAll(vertices, x => createVertexCallback(x));
            var indices           = new ushort[]
            {
                0, 1, 2, 2, 1, 3,               // X
                4, 5, 6, 6, 5, 7,               // -X
                8, 9, 10, 10, 9, 11,            // Y
                12, 13, 14, 14, 13, 15,         // -Y
                16, 17, 18, 18, 17, 19,         // Z
                20, 21, 22, 22, 21, 23,         // -Z
                1, 0, 18, 18, 19, 1,            // X,Z
                2, 3, 20, 21, 20, 3,            // X,-Z
                6, 7, 16, 17, 16, 7,            // -X,Z
                5, 4, 22, 22, 23, 5,            // -X,-Z
                3, 1, 9, 11, 9, 1,              // X,Y
                7, 5, 8, 8, 10, 7,              // -X,Y
                10, 11, 17, 19, 17, 11,         // Y,Z
                9, 8, 21, 23, 21, 8,            // Y,-Z
                0, 2, 14, 14, 15, 0,            // X,-Y
                4, 6, 12, 13, 12, 6,            // -X,-Y
                15, 13, 16, 16, 18, 15,         // Z,-Y
                12, 14, 20, 20, 22, 12,         // -Z,-Y
                11, 1, 19,                      // X,Y,Z
                3, 9, 21,                       // X,Y,-Z
                7, 10, 17,                      // -X,Y,Z
                8, 5, 23,                       // -X,Y,-Z
                0, 15, 18,                      // X,-Y,Z
                14, 2, 20,                      // X,-Y,-Z
                13, 6, 16,                      // -X,-Y,Z
                4, 12, 22,                      // -X,-Y,-Z
            };

            var ret = new BasicGeometry( );

            ret.VertexBuffer = new VertexBuffer(device, typeof(T), 24, BufferUsage.WriteOnly);
            ret.VertexBuffer.SetData(convertedVertices);
            ret.IndexBuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly);
            ret.IndexBuffer.SetData(indices);
            ret.Effect = new BasicEffect(device);
            ret.Effect.EnableDefaultLighting( );
            ret.Effect.DiffuseColor           = new Vector3(0.9f, 0.5f, 0.2f);
            ret.Effect.PreferPerPixelLighting = true;
            ret.Effect.SpecularPower          = 1000;
            ret.Effect.SpecularColor          = new Vector3(1, 1, 1);
            return(ret);
        }