public static ParticleSystemCompiledShaderData BuildGpuLogicPixelShader(IEnumerable<ParticleSystemLogicStep> steps, LogicType logicType, VertexShaderType vsType, bool useUserValues, bool useColours, bool storeLifeData, ContentTargetPlatform targetPlatform, bool useUserDataPositionBuffer, string pathToShaderSystem)
		{
			if (steps == null)
				throw new ArgumentNullException();

			StringBuilder output = new StringBuilder();
			Random random = new Random();

			foreach (ParticleSystemLogicStep step in steps)
				BuildStep(step, output, 1, random);

			//fixup the preprocssor defines
			string shaderCodeFixup = GpuParticleShaderBuilder.BaseShader.Replace("_#", "#");

			//insert the custom code
			string shaderCode = shaderCodeFixup.Replace(GpuParticleShaderBuilder.replaceMarker, output.ToString());

			//build the shader header and main method.

			StringBuilder header = new StringBuilder();
			StringBuilder methodHeader = new StringBuilder();
			StringBuilder methodPS = new StringBuilder();

			methodPS.Append("void PS(float4 texRandIndex : TEXCOORD0");

			if (logicType != LogicType.Frame)
				methodPS.Append(", float4 lifeIndex : TEXCOORD1");
			else
				methodHeader.Append("float4 lifeIndex = 0;");

			if (logicType == LogicType.Once)
			{
				methodPS.Append(", float4 defaultPosition : TEXCOORD2");
				methodPS.Append(", float4 defaultVelocity : TEXCOORD3");
				methodPS.Append(", float4 defaultColour   : TEXCOORD4");
				methodPS.Append(", float4 defaultUserData : TEXCOORD5");
			}
			else
			{
				methodHeader.Append("float4 defaultPosition = 0, defaultVelocity = 0;");
				methodHeader.Append("float4 defaultColour = 1, defaultUserData = 0;");
			}

			int colIndex = 2;

			methodPS.Append(", out float4 posOut : COLOR0, out float4 velOut : COLOR1");


			if (useColours)
				methodPS.AppendFormat(", out float4 colOut : COLOR{0}", colIndex++);
			else
				methodHeader.Append("float4 colOut = 1;");

			if (useUserValues)
				methodPS.AppendFormat(", out float4 userOut : COLOR{0}", colIndex++);
			else
				methodHeader.Append("float4 userOut = 0;");

			methodPS.AppendLine(")");
			methodPS.AppendLine("{");
			methodPS.Append("\t");
			methodPS.Append(methodHeader);
			methodPS.AppendLine();

			methodPS.Append("\t");
			methodPS.AppendLine(@"PS_Method(texRandIndex,lifeIndex, defaultPosition, defaultVelocity, defaultColour, defaultUserData,posOut, velOut, colOut, userOut);");
			methodPS.AppendLine("}");

			int colourIndex = -1, userIndex = -1, lifeIndex = -1;

			if (logicType != LogicType.Once)
			{
				int samplerIndex = 3;
				header.AppendLine();
				header.AppendLine("#define TEXTURE_PARTICLE_METHOD");
				if (useColours)
				{
					colourIndex = samplerIndex;
					header.AppendLine("#define USER_COLOUR_TEX");
					header.AppendLine(string.Format(@"sampler2D ColourSampler : register(ps,s{0});", samplerIndex++));
				}
				if (useUserValues)
				{
					userIndex = samplerIndex;
					header.AppendLine("#define USER_USER_TEX");
					header.AppendLine(string.Format(@"sampler2D UserSampler : register(ps,s{0});", samplerIndex++));
				}
				if (storeLifeData && logicType == LogicType.Frame)
				{
					lifeIndex = samplerIndex;
					header.AppendLine("#define USER_LIFE_TEX");
					header.AppendLine(string.Format(@"sampler2D LifeSampler : register(ps,s{0});", samplerIndex++));
				}

				if (logicType == LogicType.Frame || logicType == LogicType.FrameMove)
					header.AppendLine("#define ADD_VELOCITY");
			}

			switch (vsType)
			{
				case VertexShaderType.Clone:
					header.AppendLine("#define VS_CLONE");
					break;
				case VertexShaderType.Frame:
					header.AppendLine("#define VS_FRAME");
					break;
				case VertexShaderType.Once:
					header.AppendLine("#define VS_ONCE");
					break;
			}

			if (useUserDataPositionBuffer)
			{
				header.AppendLine("#define POS_WRITTEN_TO_USER");
			}


			StringBuilder completeShader = new StringBuilder();

			completeShader.Append(header);
			completeShader.AppendLine();
			completeShader.Append(shaderCode);
			completeShader.AppendLine();
			completeShader.Append(methodPS);
			completeShader.AppendLine();
			completeShader.Append(techniqueCode);
			completeShader.AppendLine();


			if (ShaderCompileDelegate == null)
				LinkToShaderCompiler(pathToShaderSystem);

			string errors;
			byte[] shaderBytes = ShaderCompileDelegate(completeShader.ToString(), "", targetPlatform == ContentTargetPlatform.Xbox360, out errors);

			if (errors != null)
				throw new InvalidOperationException("GPU Particle System Pixel Shader failed to compile:" + Environment.NewLine + errors);

			return new ParticleSystemCompiledShaderData(shaderBytes, targetPlatform == ContentTargetPlatform.Xbox360, colourIndex, userIndex, lifeIndex);
		}
		internal GpuParticleProcessorData(ParticleSystemTypeData typeData, bool useColourValues, bool usesUserValues, bool storeLifeData, ContentTargetPlatform targetPlatform, string pathToShaderSystem) : this(
			GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Once, GpuParticleShaderBuilder.LogicType.Once, GpuParticleShaderBuilder.VertexShaderType.Once, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition, pathToShaderSystem),
			GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Once, GpuParticleShaderBuilder.LogicType.OnceClone, GpuParticleShaderBuilder.VertexShaderType.Clone, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition, pathToShaderSystem),
			GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Frame, GpuParticleShaderBuilder.LogicType.Frame, GpuParticleShaderBuilder.VertexShaderType.Frame, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition, pathToShaderSystem),
			GpuParticleShaderBuilder.BuildGpuLogicPixelShader(typeData.ParticleLogicData.Frame, GpuParticleShaderBuilder.LogicType.FrameMove, GpuParticleShaderBuilder.VertexShaderType.Clone, usesUserValues, useColourValues, storeLifeData, targetPlatform, typeData.GpuBufferPosition, pathToShaderSystem))
		{
		}