/// <summary>
		/// Generate a spherical harmonic from the faces of a cubemap, treating each pixel as a light source and averaging the result.
		/// </summary>
		public static SphericalHarmonicL1RGB GenerateSphericalHarmonicFromCubeMap(
					Vector3[] colourDataPositiveX,
					Vector3[] colourDataNegativeX,
					Vector3[] colourDataPositiveY,
					Vector3[] colourDataNegativeY,
					Vector3[] colourDataPositiveZ,
					Vector3[] colourDataNegativeZ)
		{
			if (colourDataPositiveX == null ||
				colourDataNegativeX == null ||
				colourDataPositiveY == null ||
				colourDataNegativeY == null ||
				colourDataPositiveZ == null ||
				colourDataNegativeZ == null)
				throw new ArgumentNullException();

			SphericalHarmonicL1RGB sh = new SphericalHarmonicL1RGB();

			Vector3[][] source = {
				colourDataPositiveX,
				colourDataNegativeX,
				colourDataPositiveY,
				colourDataNegativeY,
				colourDataPositiveZ,
				colourDataNegativeZ,
			};

			//extract the 6 faces of the cubemap.
			for (int face = 0; face < 6; face++)
			{
				int size = (int)(Math.Sqrt(source[face].Length) + 0.5);

				if (size * size != source[face].Length)
					throw new ArgumentException("Cubemap face is an unexpected (non square) size");

				Microsoft.Xna.Framework.Graphics.CubeMapFace faceId = (Microsoft.Xna.Framework.Graphics.CubeMapFace)face;

				//get the transformation for this face,
				Matrix cubeFaceMatrix;
				Xen.Graphics.DrawTargetTextureCube.GetCubeMapFaceMatrix(faceId, out cubeFaceMatrix);

				//extract the spherical harmonic for this face and accumulate it.
				sh += ExtractSphericalHarmonicForCubeFace(cubeFaceMatrix, source[face], size);
			}

			//average out over the sphere. account for cosine weighting which doubles the output - but it's also over a full sphere not a hemisphere
			return sh / 3;
		}
		/// <summary>
		/// Multiply a spherical harmonic by a constant scale factor
		/// </summary>
		public static SphericalHarmonicL1RGB operator *(SphericalHarmonicL1RGB x, float scale)
		{
			SphericalHarmonicL1RGB o = new SphericalHarmonicL1RGB();

			o.Red.X = x.Red.X * scale; o.Red.Y = x.Red.Y * scale; o.Red.Z = x.Red.Z * scale;
			o.Blue.X = x.Blue.X * scale; o.Blue.Y = x.Blue.Y * scale; o.Blue.Z = x.Blue.Z * scale;
			o.Green.X = x.Green.X * scale; o.Green.Y = x.Green.Y * scale; o.Green.Z = x.Green.Z * scale;

			return o;
		}
		/// <summary>
		/// Divide a spherical harmonic by a constant factor
		/// </summary>
		public static SphericalHarmonicL1RGB operator /(SphericalHarmonicL1RGB x, float divider)
		{
			SphericalHarmonicL1RGB o = new SphericalHarmonicL1RGB();

			float scale = 1.0f / divider;

			o.Red.X = x.Red.X * scale; o.Red.Y = x.Red.Y * scale; o.Red.Z = x.Red.Z * scale;
			o.Blue.X = x.Blue.X * scale; o.Blue.Y = x.Blue.Y * scale; o.Blue.Z = x.Blue.Z * scale;
			o.Green.X = x.Green.X * scale; o.Green.Y = x.Green.Y * scale; o.Green.Z = x.Green.Z * scale;

			return o;
		}
		/// <summary>
		/// Add two spherical harmonics together
		/// </summary>
		public static SphericalHarmonicL1RGB operator +(SphericalHarmonicL1RGB x, SphericalHarmonicL1RGB y)
		{
			SphericalHarmonicL1RGB o = new SphericalHarmonicL1RGB();

			o.Red.X = x.Red.X + y.Red.X; o.Red.Y = x.Red.Y + y.Red.Y; o.Red.Z = x.Red.Z + y.Red.Z;
			o.Blue.X = x.Blue.X + y.Blue.X; o.Blue.Y = x.Blue.Y + y.Blue.Y; o.Blue.Z = x.Blue.Z + y.Blue.Z;
			o.Green.X = x.Green.X + y.Green.X; o.Green.Y = x.Green.Y + y.Green.Y; o.Green.Z = x.Green.Z + y.Green.Z;

			return o;
		}
		/// <summary>
		/// Linear interpolate (Lerp) between two spherical harmonics based on a interpolation factor
		/// </summary>
		/// <param name="factor">Determines the interpolation point. When factor is 1.0, the output will be <paramref name="x"/>, when factor is 0.0, the output will be <paramref name="y"/></param>
		/// <param name="result"></param>
		/// <param name="x"></param>
		/// <param name="y"></param>
		public static void Lerp(ref SphericalHarmonicL1RGB x, ref SphericalHarmonicL1RGB y, float factor, out SphericalHarmonicL1RGB result)
		{
			result = new SphericalHarmonicL1RGB();

			float xs = factor;
			float ys = 1.0f - factor;

			result.Red.X = xs * x.Red.X + ys * y.Red.X; result.Red.Y = xs * x.Red.Y + ys * y.Red.Y; result.Red.Z = xs * x.Red.Z + ys * y.Red.Z;
			result.Blue.X = xs * x.Blue.X + ys * y.Blue.X; result.Blue.Y = xs * x.Blue.Y + ys * y.Blue.Y; result.Blue.Z = xs * x.Blue.Z + ys * y.Blue.Z;
			result.Green.X = xs * x.Green.X + ys * y.Green.X; result.Green.Y = xs * x.Green.Y + ys * y.Green.Y; result.Green.Z = xs * x.Green.Z + ys * y.Green.Z;
		}
		/// <summary>
		/// Divide a spherical harmonic by a constant factor
		/// </summary>
		public static void Divide(ref SphericalHarmonicL1RGB x, float divider, out SphericalHarmonicL1RGB result)
		{
			result = new SphericalHarmonicL1RGB();

			float scale = 1.0f / divider;

			result.Red.X = x.Red.X * scale; result.Red.Y = x.Red.Y * scale; result.Red.Z = x.Red.Z * scale;
			result.Blue.X = x.Blue.X * scale; result.Blue.Y = x.Blue.Y * scale; result.Blue.Z = x.Blue.Z * scale;
			result.Green.X = x.Green.X * scale; result.Green.Y = x.Green.Y * scale; result.Green.Z = x.Green.Z * scale;
		}
		/// <summary>
		/// Multiply a spherical harmonic by a constant scale factor
		/// </summary>
		public static void Multiply(ref SphericalHarmonicL1RGB x, float scale, out SphericalHarmonicL1RGB result)
		{
			result = new SphericalHarmonicL1RGB();

			result.Red.X = x.Red.X * scale; result.Red.Y = x.Red.Y * scale; result.Red.Z = x.Red.Z * scale;
			result.Blue.X = x.Blue.X * scale; result.Blue.Y = x.Blue.Y * scale; result.Blue.Z = x.Blue.Z * scale;
			result.Green.X = x.Green.X * scale; result.Green.Y = x.Green.Y * scale; result.Green.Z = x.Green.Z * scale;
		}
		/// <summary>
		/// Add two spherical harmonics together
		/// </summary>
		public static void Add(ref SphericalHarmonicL1RGB x, ref SphericalHarmonicL1RGB y, out SphericalHarmonicL1RGB result)
		{
			result = new SphericalHarmonicL1RGB();

			result.Red.X = x.Red.X + y.Red.X; result.Red.Y = x.Red.Y + y.Red.Y; result.Red.Z = x.Red.Z + y.Red.Z;
			result.Blue.X = x.Blue.X + y.Blue.X; result.Blue.Y = x.Blue.Y + y.Blue.Y; result.Blue.Z = x.Blue.Z + y.Blue.Z;
			result.Green.X = x.Green.X + y.Green.X; result.Green.Y = x.Green.Y + y.Green.Y; result.Green.Z = x.Green.Z + y.Green.Z;
		}