public static SourceShader Create(string shaderSource, string filename)
		{
			SourceShader ss = null;
			string dir = Directory.GetCurrentDirectory();
			try
			{
				Directory.SetCurrentDirectory(new FileInfo(filename).Directory.FullName);

				ss = new SourceShader(shaderSource, filename, null);
				ss.ExtractAsmTechniques(null);

				if (!ss.manualExtensions)
				{
					try
					{
						int line;
						shaderSource = ShaderExtensionGenerator.GenerateShaderCode(ss, "", ss.mixedMode, out line);
						ss = new SourceShader(shaderSource, filename, null);
						ss.generatedLineStart = line;
						ss.ExtractAsmTechniques(null);
					}
					catch (Exception ex)
					{
						ShaderExtensionGenerator.ThrowGeneratorError(ex.ToString(), filename);
					}
				}
			}
			finally
			{
				Directory.SetCurrentDirectory(dir);
			}
			return ss;
		}
		public SourceDom(SourceShader shader, string baseNamespace, CodeDomProvider provider)
		{
			this.codeProvider = provider;
			this.directives = new CompileDirectives(provider);
			this.source = shader;
			this.baseNamespace = baseNamespace;
			
			string namespaceName = baseNamespace;
			if (!shader.UseParentNamespace)
				namespaceName += "." + Common.ToUpper(Path.GetFileNameWithoutExtension(source.FileName));
			this.outputNamespace = namespaceName;

			HlslTechnique[] techniques = shader.GetAllTechniques();

			if (shader.DefinePlatform)
			{
				//create a copy for each platform
				//xbox first

				this.rootPcNamespace = new CodeNamespace(namespaceName);
				this.rootXboxNamespace = new CodeNamespace(namespaceName);
				
				for (int i = 0; i < techniques.Length; i++)
				{
					//build the PC shaders
					if ((techniques[i].Platform & Platform.Windows) == Platform.Windows)
					{
						ShaderDom dom = new ShaderDom(source, techniques[i].Name, Platform.Windows, directives);
						this.rootPcNamespace.Types.Add(dom.CodeTypeDeclaration);
					}
				}

				for (int i = 0; i < techniques.Length; i++)
				{
					//build the xbox shaders
					if ((techniques[i].Platform & Platform.Xbox) == Platform.Xbox)
					{
						ShaderDom dom = new ShaderDom(source, techniques[i].Name, Platform.Xbox, directives);
						this.rootXboxNamespace.Types.Add(dom.CodeTypeDeclaration);
					}
				}
			}
			else
			{
				this.rootNamespace = new CodeNamespace(namespaceName);

				for (int i = 0; i < techniques.Length; i++)
				{
					//build the combined pc / xbox shaders
					if ((techniques[i].Platform & Platform.Both) == Platform.Both)
					{
						ShaderDom dom = new ShaderDom(source, techniques[i].Name, Platform.Both, directives);
						this.rootNamespace.Types.Add(dom.CodeTypeDeclaration);
					}
				}
			}
		}
		public static string GenerateShaderCode(SourceShader shader, string techniquePostfix, bool mixedModeOutput, out int startLine)
		{
			string noTechniques = TechniqueRemover.Process(shader);
			
			startLine = 1;
			for (int i = 0; i < noTechniques.Length; i++)
			{
				if (noTechniques[i] == '\n')
					startLine++;
			}


			if (shader.GenerateInternalClass ||
				shader.UseParentNamespace ||
				shader.DefinePlatform ||
				shader.ExposeRegisters)
			{
				//recreate the extensions flag, if needed
				StringBuilder newExtensons = new StringBuilder("//CompilerOptions = ");

				if (shader.GenerateInternalClass) newExtensons.Append("internalclass, ");
				if (shader.UseParentNamespace) newExtensons.Append("parentnamespace, ");
				if (shader.DefinePlatform) newExtensons.Append("defineplatform, ");
				if (shader.ExposeRegisters) newExtensons.Append("exposeregisters");
				newExtensons.AppendLine();
				
				if (noTechniques.Length > 1 && noTechniques.Substring(0, 2) == Environment.NewLine)
					noTechniques = noTechniques.Substring(2);

				newExtensons.Append(noTechniques);
				noTechniques = newExtensons.ToString();
			}

			if (!mixedModeOutput)
			{
				//separate platforms
				string xbox = new ShaderExtensionGenerator(shader, Platform.Xbox, techniquePostfix).result;
				string pc = new ShaderExtensionGenerator(shader, Platform.Windows, techniquePostfix).result;
				return string.Format(@"{0}

#ifdef XBOX360
{1}
#else
{2}
#endif", noTechniques, xbox, pc);
			}
			else
			{
				string both = new ShaderExtensionGenerator(shader, Platform.Both, techniquePostfix).result;

				return string.Format(@"{0}

{1}",noTechniques, both);
			}
		}
Beispiel #4
0
        private void ExtractIncludeSource(ref bool useVfetch)
        {
            if (filename != null)
            {
                //parse the hs, look for #include's in the root level only

                foreach (HlslStructure hs in this.hlslShader.Children)
                {
                    if (hs.Elements.Length > 4)
                    {
                        if (hs.Elements[0] == "#" &&
                            hs.Elements[1] == "include")
                        {
                            bool          global = hs.Elements[2] == "<";
                            StringBuilder file   = new StringBuilder();

                            for (int i = 3; i < hs.Elements.Length - 1; i++)
                            {
                                if ((global && hs.Elements[i] == ">") || (!global && hs.Elements[i] == "\""))
                                {
                                    break;
                                }

                                file.Append(hs.Elements[i]);
                            }

                            string includeName = file.ToString();

                            if (includeName == VFetchIncludeHandler.IncludeSymbol)
                            {
                                //vfetch requires shaders are built separately
                                useVfetch = true;
                            }
                            else
                            {
                                //find the file
                                string path = VFetchIncludeHandler.ResolveIncludePath(file.ToString(), this.filename);

                                if (File.Exists(path))
                                {
                                    //load the file and parse it as well
                                    SourceShader include = new SourceShader(File.ReadAllText(path), path, false);
                                    includedSource.Add(include);
                                }
                            }
                        }
                    }
                }
            }
        }
		public ConstantSetup(SourceShader source, string techniqueName, Platform platform)
		{
			this.source = source;
			this.techniqueName = techniqueName;

			this.attributeNames = new List<string>();
			this.attributeFields = new List<CodeFieldReferenceExpression>();
			this.attributeArrayFields = new List<CodeFieldReferenceExpression>();
			this.attributeAssignment = new Dictionary<Type, List<CodeStatement>>();
			this.semanticMapping = new List<SemanticMapping>();
			this.globals = new List<GlobalAttribute>();

			this.asm = source.GetAsmTechnique(techniqueName, platform);

			ComputeAllValidSemantics();
		}
		public VFetchXboxMethodExtractor(SourceShader shader, HlslTechnique technique)
		{
			this.source = shader;

			HlslMethod method = shader.GetMethod(technique.VertexShaderMethodName, Platform.Xbox);
			if (method != null && method.UsesVFetch)
			{
				vsCode = ProcessMethod(method, technique.VertexShaderArgs, ShaderProfile.VS_3_0);
			}

			method = shader.GetMethod(technique.PixelShaderVersion, Platform.Xbox); //pixel shader using vfetch?!
			if (method != null && method.UsesVFetch)
			{
				psCode = ProcessMethod(method, technique.PixelShaderArgs, ShaderProfile.PS_3_0);
			}
		}
Beispiel #7
0
        public VFetchXboxMethodExtractor(SourceShader shader, HlslTechnique technique)
        {
            this.source = shader;

            HlslMethod method = shader.GetMethod(technique.VertexShaderMethodName, Platform.Xbox);

            if (method != null && method.UsesVFetch)
            {
                vsCode = ProcessMethod(method, technique.VertexShaderArgs, ShaderProfile.VS_3_0);
            }

            method = shader.GetMethod(technique.PixelShaderVersion, Platform.Xbox);             //pixel shader using vfetch?!
            if (method != null && method.UsesVFetch)
            {
                psCode = ProcessMethod(method, technique.PixelShaderArgs, ShaderProfile.PS_3_0);
            }
        }
Beispiel #8
0
 private void ValidatePixleShaderInput(SourceShader source, Platform platform)
 {
     if (psListing != null && vsListing != null)
     {
         for (int i = 0; i < psListing.InputCount; i++)
         {
             if (!vsListing.ContainsOutput(psListing.GetInput(i)))
             {
                 throw new CompileException(string.Format(
                                                "Pixel Shader '{0}' for Technique '{1}' tries to access input '{2} {3}', which is not output by Vertex Shader '{4}'{5}(Use the CompilerOption 'SkipConstantValidation' to disable this check)",
                                                source.GetTechnique(name, platform).PixelShaderMethodName,
                                                name,
                                                psListing.GetInput(i).Usage,
                                                psListing.GetInput(i).Index,
                                                source.GetTechnique(name, platform).VertexShaderMethodName,
                                                Environment.NewLine));
             }
         }
     }
 }
		public Preshaders(SourceShader source, string techniqueName, Platform platform)
		{
			technique = source.GetAsmTechnique(techniqueName, platform);

			if (technique.PixelPreShader != null)
			{
				pixelPreShaderStatements = new CodeStatementCollection();
				pixelPreShader = new PreshaderSrc(technique.PixelPreShader, pixelPreShaderStatements);

				technique.PixelShader.RegisterSet.SetMinFloatRegisterCount(pixelPreShader.MaxConstantRegisterAccess);
				technique.PixelShader.RegisterSet.SetMinBooleanRegisterCount(pixelPreShader.MaxBooleanConstantRegisterWrite);
			}

			if (technique.VertexPreShader != null)
			{
				vertexPreShaderStatements = new CodeStatementCollection();
				vertexPreShader = new PreshaderSrc(technique.VertexPreShader, vertexPreShaderStatements);

				technique.VertexShader.RegisterSet.SetMinFloatRegisterCount(vertexPreShader.MaxConstantRegisterAccess);
				technique.VertexShader.RegisterSet.SetMinBooleanRegisterCount(vertexPreShader.MaxBooleanConstantRegisterWrite);
			}
		}
		public ShaderRegisters(SourceShader source, string techniqueName, Platform platform, IExtensionStatementProvider extensionStatementProvider)
		{
			AsmTechnique technique = source.GetAsmTechnique(techniqueName, platform);
			this.extensionStatementProvider = extensionStatementProvider;

			vsReg = technique.VertexShader.RegisterSet;
			psReg = technique.PixelShader.RegisterSet;

			if (technique.InstancingShader != null)
				vsInstancingReg = technique.InstancingShader.RegisterSet;
			if (technique.BlendingShader != null)
				vsBlendingReg = technique.BlendingShader.RegisterSet;

			if (technique.TechniqueExtraData != null)
			{
				this.techniqueData = technique.TechniqueExtraData;

				psDefault = technique.TechniqueExtraData.PixelShaderConstants;
				vsDefault = technique.TechniqueExtraData.VertexShaderConstants;

				psBooleanDefault = technique.TechniqueExtraData.PixelShaderBooleanConstants;
				vsBooleanDefault = technique.TechniqueExtraData.VertexShaderBooleanConstants;
			}
		}
		private void GenerateTechnique(SourceShader shader, HlslTechnique technique, AsmTechnique asmTechnique, Platform platform)
		{
			string blendVS = ProcessTechniqueVS(shader, technique, asmTechnique, ShaderExtension.Blending, platform);
			string instVS = ProcessTechniqueVS(shader, technique, asmTechnique, ShaderExtension.Instancing, platform);
			
			footer.AppendLine();

			////append the new technique
			string techniqueName = technique.Name + techniquePostfix;
			string code = @"
technique {0} {11}
{9}
	pass
	{9}
		VertexShader = compile {1} {5}({6});
		PixelShader = compile {2} {3}({4});
	{10}
	pass Blending
	{9}
		VertexShader = compile {1} {7}({6});
	{10}
	pass Instancing
	{9}
		VertexShader = compile {1} {8}({6});
	{10}
{10}
";

			var annotation = new StringBuilder();

			var asm = shader.GetAsmTechnique(technique.Name, platform);

			if (asm != null && asm.TechniqueExtraData != null &&
				asm.TechniqueExtraData.ClassBaseTypes != null && asm.TechniqueExtraData.ClassBaseTypes.Length > 0)
			{
				annotation.Append("< string  BaseTypes = \"");

				bool first = true;
				foreach (var baseType in asm.TechniqueExtraData.ClassBaseTypes)
				{
					if (!first)
						annotation.Append(", ");
					first = false;
					annotation.Append(baseType);
				}

				annotation.Append("\"; >");
			}
			
			footer.AppendFormat(
				code,
				techniqueName,
				technique.GetVertexShaderVersion(platform),
				technique.GetPixelShaderVersion(platform),
				technique.PixelShaderMethodName,
				CombineArgs(technique.PixelShaderArgs),
				technique.VertexShaderMethodName,
				CombineArgs(technique.VertexShaderArgs),
				blendVS,
				instVS,
				"{","}",
				annotation);

		}
		private void ExtractIncludeSource()
		{
			if (filename != null)
			{
				//parse the hs, look for #include's in the root level only

				foreach (HlslStructure hs in this.hlslShader.Children)
				{
					if (hs.Elements.Length > 4)
					{
						if (hs.Elements[0] == "#" &&
							hs.Elements[1] == "include")
						{
							bool global = hs.Elements[2] == "<";
							StringBuilder file = new StringBuilder();

							for (int i = 3; i < hs.Elements.Length-1; i++)
							{
								if ((global && hs.Elements[i] == ">") || (!global && hs.Elements[i] == "\""))
									break;

								file.Append(hs.Elements[i]);
							}

							string includeName = file.ToString();

							//find the file
							string path = Path.IsPathRooted(file.ToString()) ? file.ToString() : Path.Combine(Path.GetDirectoryName(filename), file.ToString());

							if (File.Exists(path))
							{
								//load the file and parse it as well
								SourceShader include = new SourceShader(File.ReadAllText(path), path, null);
								includedSource.Add(include);
							}
						}
					}
				}
			}
		}
		//this is a bit of a hack.
		//it relies on the fact that the DirectX shader compiler
		//marks up the disasembled shader with comments detailing the shader inputs.
		public static AsmTechnique[] ExtractTechniques(SourceShader shader, Platform platform, out DecompiledEffect fx, string generatedPrefix)
		{
			//decompile the shader
			fx = new DecompiledEffect(shader, platform);

			//break it up into techniques
			Tokenizer assemblyTokens = new Tokenizer(fx.DecompiledAsm, false, true, true);

			List<AsmTechnique> techniqes = new List<AsmTechnique>();

			while (assemblyTokens.NextToken())
			{
				if (assemblyTokens.Token.Equals("technique", StringComparison.InvariantCultureIgnoreCase))
				{
					//should be format:
					//technique NAME
					//{
					//}

					assemblyTokens.NextToken();
					string name = assemblyTokens.Token;

					if (generatedPrefix != null)
					{
						//only include generated techniques
						if (name.EndsWith(generatedPrefix))
							name = name.Substring(0, name.Length - generatedPrefix.Length);
						else
							continue;
					}

					assemblyTokens.NextToken();

					//may be a line break
					if (assemblyTokens.Token.Trim().Length == 0)
						assemblyTokens.NextToken();

					//should be a {
					if (assemblyTokens.Token != "{")
						throw new CompileException("Unexpected token in assembly technique declaration, expected '{': " + assemblyTokens.Token);

					// read the entire technique {} block
					if (!assemblyTokens.ReadBlock())
						throw new CompileException("Unexpected end of string in assembly technique pass declaration");

					AsmTechnique asm = new AsmTechnique(name, assemblyTokens.Token, fx.GetTechniqueDefaultValues(name));

					if (!shader.SkipConstantValidation)
					{
						//do some extra validation to make sure pixel inputs match vertex outputs
						asm.ValidatePixleShaderInput(shader, platform);
					}

					techniqes.Add(asm);
				}
			}

			for (int i = 0; i < techniqes.Count; i++)
			{
				techniqes[i].MergeSemantics(fx.EffectRegisters);
			}

			return techniqes.ToArray();
		}
		private void ExtractEffectDefaults(Effect effect, List<Register> textures, SourceShader source, Platform platform)
		{
			//nasty-ness ensues!
			GraphicsDevice device = Graphics.GraphicsDevice;

			int maxVsConst = 256;
			int maxPsConst = 32;

			int maxPsTextures = 16;
			int maxVsTextures = 4;

			bool[] shaderBooleanConstants = new bool[16];

			List<Texture> allTextures = new List<Texture>();

			foreach (EffectTechnique technique in effect.Techniques)
			{
				//Thanks to Darren Grant (again :)
				//annotate a Technique with 'BaseTypes' and the generates class will inherit from those types
				string[] baseTypes = new string[0];
				foreach (EffectAnnotation annotation in technique.Annotations)
				{
					if (annotation.Name.Equals("BaseTypes", StringComparison.InvariantCulture) ||
						annotation.Name.Equals("BaseType", StringComparison.InvariantCulture))
					{
						baseTypes = annotation.GetValueString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

						for (int i = 0; i < baseTypes.Length; i++)
							baseTypes[i] = baseTypes[i].Trim();
					}
				}

				float[] psConstants = new float[maxPsConst * 4]; // pixel 
				float[] vsConstants = new float[maxVsConst * 4]; // not-pixel 

				TextureSamplerState[] psSamplers = new TextureSamplerState[maxPsTextures];
				TextureSamplerState[] vsSamplers = new TextureSamplerState[maxVsTextures];

				int[] psTexturesIndex = new int[maxPsTextures];
				int[] vsTexturesIndex = new int[maxVsTextures];

				int[] psBooleanConstants = new int[16];
				int[] vsBooleanConstants = new int[16];

				allTextures.Clear();

				Dictionary<string, Vector4[]> techniqueSingleValues = new Dictionary<string, Vector4[]>();

				//get the device
				object devicePtr = device.GetType().GetField("pComPtr", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(device);
				var deviceInterop = new Xen.Graphics.ShaderSystem.Native.DeviceInterop((System.Reflection.Pointer)devicePtr);

				try
				{
					//I'm sure XNA won't mind...
					deviceInterop.ZeroShaderConstants();

					for (int i = 0; i < maxPsTextures; i++)
					{
						deviceInterop.SetTextureFilters(i, false);
						ResetSampler(device, i, true);
					}
					for (int i = 0; i < maxVsTextures; i++)
					{
						deviceInterop.SetTextureFilters(i, true);
						ResetSampler(device, i, false);
					}

					//assign the technique textures
					foreach (Register texReg in textures)
					{
						Type type = Common.GetTextureType(texReg.Type);
						Texture tex = Graphics.BeginGetTempTexture(type);
						effect.Parameters[texReg.Name].SetValue(tex);

						allTextures.Add(tex);
					}

					//bind the effect technique
					effect.CurrentTechnique = technique;

					if (technique.Passes.Count > 0)
					{
						EffectPass pass = technique.Passes[0];
						pass.Apply();
					}


					foreach (var param in effect.Parameters)
					{
						try
						{
							if (param.ParameterType == EffectParameterType.Single ||
								param.ParameterType == EffectParameterType.Int32)
							{
								Vector4[] values = param.GetValueVector4Array(param.RowCount);
								techniqueSingleValues.Add(param.Name, values);
							}
						}
						catch
						{
						}
					}


					//all done. Now read back what has changed. :D
					deviceInterop.GetShaderConstantsPS(psConstants);
					deviceInterop.GetShaderConstantsVS(vsConstants);
					//psConstants = device.GetPixelShaderVector4ArrayConstant(0, maxPsConst);
					//vsConstants = device.GetVertexShaderVector4ArrayConstant(0, maxVsConst);

					for (int i = 0; i < maxPsTextures; i++)
						psSamplers[i] = GetState(device, deviceInterop, i, true, allTextures, out psTexturesIndex[i]);

					for (int i = 0; i < maxVsTextures; i++)
						vsSamplers[i] = GetState(device, deviceInterop, i, false, allTextures, out vsTexturesIndex[i]);

					for (int i = 0; i < allTextures.Count; i++)
						Graphics.EndGetTempTexture(allTextures[i]);
					allTextures.Clear();

					deviceInterop.GetShaderConstantsPS(psBooleanConstants);
					deviceInterop.GetShaderConstantsVS(vsBooleanConstants);
					//vsBooleanConstants = device.GetVertexShaderBooleanConstant(0, 16);
					//psBooleanConstants = device.GetPixelShaderBooleanConstant(0, 16);
				}
				catch
				{
					//something went wrong... Eg, binding a SM 3.0 shader on SM 2.0 hardware device

					throw new CompileException("An unexpected error occured while compiling shader: The DirectX device may not be XNA 'HiDef' capable");
				}

				TechniqueExtraData defaults = new TechniqueExtraData();

				defaults.PixelSamplerStates = psSamplers;
				defaults.PixelShaderConstants = Convert(psConstants);
				defaults.VertexSamplerStates = vsSamplers;
				defaults.VertexShaderConstants = Convert(vsConstants);
				defaults.PixelSamplerTextureIndex = psTexturesIndex;
				defaults.VertexSamplerTextureIndex = vsTexturesIndex;
				defaults.TechniqueTextures = textures.ToArray();
				defaults.ClassBaseTypes = baseTypes;
				defaults.PixelShaderBooleanConstants = Convert(psBooleanConstants);
				defaults.VertexShaderBooleanConstants = Convert(vsBooleanConstants);
				defaults.DefaultSingleValues = techniqueSingleValues;

				if (this.techniqueDefaults.ContainsKey(technique.Name) == false)
					this.techniqueDefaults.Add(technique.Name, defaults);
			}
		}
Beispiel #15
0
        public DecompiledEffect(SourceShader source, Platform platform)
        {
            CompilerMacro[] macros = null;
            if (platform == Platform.Xbox)
            {
                macros = XboxCompileMacros;
            }

            CompilerIncludeHandler include = null;
            TargetPlatform         target  = TargetPlatform.Windows;

            this.techniqueDefaults = new Dictionary <string, TechniqueExtraData>();

            if (platform != Platform.Both)
            {
                include = new VFetchIncludeHandler(source.FileName, true);                 //ALWAYS target the PC for the vfetch macro
            }
            else
            {
                include = new VFetchIncludeHandler(source.FileName);                 //Acts as a generic handler
            }
            CompiledEffect compiledEffect = Effect.CompileEffectFromSource(source.ShaderSource, macros, include, source.CompilerOptions, target);

            if (!compiledEffect.Success)
            {
                Common.ThrowError(compiledEffect.ErrorsAndWarnings, source.ShaderSource);
            }

            //now pull the good stuff out.
            using (EffectPool pool = new EffectPool())
                using (Effect effect = new Effect(Graphics.GraphicsDevice, compiledEffect.GetEffectCode(), CompilerOptions.None, pool))
                {
                    Register[]      registers = new Register[effect.Parameters.Count];
                    List <Register> textures  = new List <Register>();

                    for (int i = 0; i < registers.Length; i++)
                    {
                        if (effect.Parameters[i].ParameterType == EffectParameterType.Single ||
                            effect.Parameters[i].ParameterType == EffectParameterType.Int32 ||
                            effect.Parameters[i].ParameterType == EffectParameterType.Bool)
                        {
                            registers[i].Name     = effect.Parameters[i].Name;
                            registers[i].Semantic = effect.Parameters[i].Semantic;
                        }

                        if (effect.Parameters[i].ParameterType >= EffectParameterType.Texture &&
                            effect.Parameters[i].ParameterType <= EffectParameterType.TextureCube)
                        {
                            EffectParameterType type = effect.Parameters[i].ParameterType;
                            if (type == EffectParameterType.Texture1D)
                            {
                                type = EffectParameterType.Texture2D;
                            }

                            registers[i].Name     = effect.Parameters[i].Name;
                            registers[i].Semantic = effect.Parameters[i].Semantic;
                            registers[i].Type     = type.ToString();
                            textures.Add(registers[i]);
                        }
                    }

                    this.effectRegisters = new RegisterSet(registers);
                    this.decompiledAsm   = Effect.Disassemble(effect, false);

                    ExtractEffectDefaults(effect, textures, source, platform);
                }
        }
Beispiel #16
0
        private void ExtractEffectDefaults(Effect effect, List <Register> textures, SourceShader source, Platform platform)
        {
            //nasty-ness ensues!
            GraphicsDevice device = Graphics.GraphicsDevice;

            int maxVsConst = device.GraphicsDeviceCapabilities.MaxVertexShaderConstants;
            int maxPsConst = 32;

            int maxPsTextures = 16;
            int maxVsTextures = 4;

            bool setPsBooleanConstants = device.GraphicsDeviceCapabilities.PixelShaderVersion.Major == 3;

            bool[] shaderBooleanConstants = new bool[16];

            List <Texture> allTextures = new List <Texture>();

            foreach (EffectTechnique technique in effect.Techniques)
            {
                //Thanks to Darren Grant (again :)
                //annotate a Technique with 'BaseTypes' and the generates class will inherit from those types
                string[] baseTypes = new string[0];
                foreach (EffectAnnotation annotation in technique.Annotations)
                {
                    if (annotation.Name.Equals("BaseTypes", StringComparison.InvariantCulture) ||
                        annotation.Name.Equals("BaseType", StringComparison.InvariantCulture))
                    {
                        baseTypes = annotation.GetValueString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                        for (int i = 0; i < baseTypes.Length; i++)
                        {
                            baseTypes[i] = baseTypes[i].Trim();
                        }
                    }
                }

                Vector4[] psConstants = new Vector4[maxPsConst];                 // pixel
                Vector4[] vsConstants = new Vector4[maxVsConst];                 // not-pixel

                TextureSamplerState[] psSamplers = new TextureSamplerState[maxPsTextures];
                TextureSamplerState[] vsSamplers = new TextureSamplerState[maxVsTextures];

                int[] psTexturesIndex = new int[maxPsTextures];
                int[] vsTexturesIndex = new int[maxVsTextures];

                bool[] psBooleanConstants = new bool[16];
                bool[] vsBooleanConstants = new bool[16];

                allTextures.Clear();

                Dictionary <string, Vector4[]> techniqueSingleValues = new Dictionary <string, Vector4[]>();

                try
                {
                    device.SetPixelShaderConstant(0, psConstants);
                    device.SetVertexShaderConstant(0, vsConstants);

                    device.SetVertexShaderConstant(0, shaderBooleanConstants);
                    if (setPsBooleanConstants)
                    {
                        device.SetPixelShaderConstant(0, shaderBooleanConstants);
                    }

                    for (int i = 0; i < maxPsTextures; i++)
                    {
                        ResetSampler(device, i, true);
                    }
                    for (int i = 0; i < maxVsTextures; i++)
                    {
                        ResetSampler(device, i, false);
                    }

                    //assign the technique textures
                    foreach (Register texReg in textures)
                    {
                        Type    type = Common.GetTextureType(texReg.Type);
                        Texture tex  = Graphics.BeginGetTempTexture(type);
                        effect.Parameters[texReg.Name].SetValue(tex);

                        allTextures.Add(tex);
                    }

                    //bind the effect technique
                    effect.CurrentTechnique = technique;
                    effect.Begin();

                    if (technique.Passes.Count > 0)
                    {
                        EffectPass pass = technique.Passes[0];
                        pass.Begin();


                        pass.End();
                    }

                    effect.End();



                    foreach (var param in effect.Parameters)
                    {
                        try
                        {
                            if (param.ParameterType == EffectParameterType.Single ||
                                param.ParameterType == EffectParameterType.Int32)
                            {
                                Vector4[] values = param.GetValueVector4Array(param.RowCount);
                                techniqueSingleValues.Add(param.Name, values);
                            }
                        }
                        catch
                        {
                        }
                    }


                    //all done. Now read back what has changed. :D

                    psConstants = device.GetPixelShaderVector4ArrayConstant(0, maxPsConst);
                    vsConstants = device.GetVertexShaderVector4ArrayConstant(0, maxVsConst);

                    for (int i = 0; i < maxPsTextures; i++)
                    {
                        psSamplers[i] = GetState(device, i, true, allTextures, out psTexturesIndex[i]);
                    }

                    for (int i = 0; i < maxVsTextures; i++)
                    {
                        vsSamplers[i] = GetState(device, i, false, allTextures, out vsTexturesIndex[i]);
                    }

                    for (int i = 0; i < allTextures.Count; i++)
                    {
                        Graphics.EndGetTempTexture(allTextures[i]);
                    }
                    allTextures.Clear();

                    vsBooleanConstants = device.GetVertexShaderBooleanConstant(0, 16);
                    psBooleanConstants = device.GetPixelShaderBooleanConstant(0, 16);
                }
                catch
                {
                    //something went wrong... Eg, binding a SM 3.0 shader on SM 2.0 hardware device
                    //Need to be running the Reference device

                    throw new CompileException("Unable to compile shader: The DirectX Reference Device may be missing (Is the DirectX SDK Installed?)");
                }

                TechniqueExtraData defaults = new TechniqueExtraData();

                defaults.PixelSamplerStates           = psSamplers;
                defaults.PixelShaderConstants         = psConstants;
                defaults.VertexSamplerStates          = vsSamplers;
                defaults.VertexShaderConstants        = vsConstants;
                defaults.PixelSamplerTextureIndex     = psTexturesIndex;
                defaults.VertexSamplerTextureIndex    = vsTexturesIndex;
                defaults.TechniqueTextures            = textures.ToArray();
                defaults.ClassBaseTypes               = baseTypes;
                defaults.PixelShaderBooleanConstants  = psBooleanConstants;
                defaults.VertexShaderBooleanConstants = vsBooleanConstants;
                defaults.DefaultSingleValues          = techniqueSingleValues;

                if (this.techniqueDefaults.ContainsKey(technique.Name) == false)
                {
                    this.techniqueDefaults.Add(technique.Name, defaults);
                }
            }
        }
		public DecompiledEffect(SourceShader source, Platform platform)
		{
			this.techniqueDefaults = new Dictionary<string, TechniqueExtraData>();

			var handler = new EffectHandler();
			handler.source = source.ShaderSource;
			handler.filename = source.FileName;
			handler.buildForXbox = platform == Platform.Xbox;

			//create the native DX decompiler wrapper
			var decompiler = new Native.ShaderDecompiler(ASCIIEncoding.ASCII.GetBytes(source.ShaderSource), source.FileName, platform == Platform.Xbox, handler);
			
			Effect effect = handler.Effect;

			if (decompiler.Errors != null && decompiler.GetShaderCode() == null)
				Common.ThrowError(decompiler.Errors);
			
			//now pull the good stuff out.

			List<Register> registers = new List<Register>();
			List<Register> textures = new List<Register>();

			for (int i = 0; i < effect.Parameters.Count; i++)
			{
				Register register = new Register();

				if (effect.Parameters[i].ParameterType == EffectParameterType.Single ||
					effect.Parameters[i].ParameterType == EffectParameterType.Int32 ||
					effect.Parameters[i].ParameterType == EffectParameterType.Bool)
				{
					register.Name = effect.Parameters[i].Name;
					register.Semantic = effect.Parameters[i].Semantic;
					register.ArraySize = effect.Parameters[i].Elements.Count;
					register.Size = effect.Parameters[i].RowCount * Math.Max(1, register.ArraySize);
					registers.Add(register);
				}

				if (effect.Parameters[i].ParameterType >= EffectParameterType.Texture &&
					effect.Parameters[i].ParameterType <= EffectParameterType.TextureCube)
				{
					EffectParameterType type = effect.Parameters[i].ParameterType;
					if (type == EffectParameterType.Texture1D)
						type = EffectParameterType.Texture2D;

					register.Name = effect.Parameters[i].Name;
					register.Semantic = effect.Parameters[i].Semantic;
					register.Type = type.ToString();
					textures.Add(register);
					register.Category = RegisterCategory.Texture;
					registers.Add(register);
				}

			}

			//iterate the samplers (XNA 4 removed the ability to query samplers!)
			var samplers = decompiler.GetSamplers();
			for (int i = 0; i < samplers.Length; i++)
			{
				var sampler = new Register();
				sampler.Name = samplers[i].Name;
				sampler.Semantic = samplers[i].Semantic;
				sampler.Type = samplers[i].Type;
				sampler.Category = RegisterCategory.Sampler;
				registers.Add(sampler);
			}
			
			//null any empty semantics
			for (int i = 0; i < registers.Count; i++)
			{
				Register reg = registers[i];
				if (reg.Semantic != null && reg.Semantic.Length == 0)
					reg.Semantic = null;
				registers[i] = reg;
			}

			this.effectRegisters = new RegisterSet(registers.ToArray());
			this.decompiledAsm = decompiler.DisassembledCode;

			ExtractEffectDefaults(effect, textures, source, platform);

			effect.Dispose();
			effect = null;
		}
		private TechniqueRemover(SourceShader shader)
		{
			techniques = new HashSet<HlslStructure>();
			foreach (var tech in shader.GetAllTechniques())
				techniques.Add(tech.HlslShader);

			result = new StringBuilder();
			shader.HlslShader.ToString(result, 0, this, null, false, true);
		}
		private void ValidatePixleShaderInput(SourceShader source, Platform platform)
		{
			if (psListing != null && vsListing != null)
			{
				for (int i = 0; i < psListing.InputCount; i++)
				{
					if (!vsListing.ContainsOutput(psListing.GetInput(i)))
					{
						throw new CompileException(string.Format(
							"Pixel Shader '{0}' for Technique '{1}' tries to access input '{2} {3}', which is not output by Vertex Shader '{4}'{5}(Use the CompilerOption 'SkipConstantValidation' to disable this check)",
							source.GetTechnique(name, platform).PixelShaderMethodName,
							name,
							psListing.GetInput(i).Usage,
							psListing.GetInput(i).Index,
							source.GetTechnique(name, platform).VertexShaderMethodName,
							Environment.NewLine));
					}
				}
			}
		}
		private static string[] SanitizeConversionErrorMessage(string errors, string source, string original, SourceShader shader)
		{
			CompileException compileException = null;
			try
			{
				List<string> errorList = new List<string>();
				string[] lines = errors.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
				StringBuilder output = new StringBuilder(errors.Length);

				string[] sourceLines = source.Split('\n');
				string[] originalLines = original.Split('\n');

				foreach (string line in lines)
				{
					if (line.Length > 1 && line[0] == '(')
					{
						//write the previous error out, if it exists
						if (output.Length > 0)
						{
							errorList.Add(output.ToString());
							output.Length = 0;
						}

						//ok, this might be a line error.
						string number = "";
						string lineNumberStr = null;
						for (int i = 1; i < line.Length - 1; i++)
						{
							if (line[i] == ')')
							{
								if (line[i + 1] != ':')
									number = "";// invalid
								break;
							}
							if (char.IsNumber(line[i]))
								number += line[i];
							else
							{
								if (line[i] == ',')
								{
									lineNumberStr = number;
									number = "";
								}
								else
								{
									number = ""; // invalid
									break;
								}
							}
						}
						if (lineNumberStr == null)
						{
							lineNumberStr = number;
							number = "0";
						}

						int lineNumber;
						if (lineNumberStr.Length > 0 && int.TryParse(lineNumberStr, out lineNumber) && lineNumber > 0 && lineNumber <= sourceLines.Length)
						{
							//find an error line reindex,
							int remapLine = -1;
							int reps = 4;	//look back at most 4 lines
							while (lineNumber-- > 0 && remapLine == -1 && reps-- > 0)
							{
								string errorLine = sourceLines[lineNumber];

								//find any '/*NUMBER*/' blocks, which remap to source line
								for (int i = 0; i < errorLine.Length - 1; i++)
								{
									if (errorLine[i] == '/' && errorLine[i + 1] == '*')
									{
										//this could be it.
										string remapLineStr = "";
										for (int n = i + 2; n < errorLine.Length - 2; n++)
										{
											if (char.IsNumber(errorLine[n]))
												remapLineStr += errorLine[n];
											else
											{
												if (!(errorLine[n] == '*' && errorLine[n + 1] == '/'))
													remapLineStr = "";	//invalid
												break;
											}
										}
										int lineIdx;
										if (remapLineStr.Length > 0 && int.TryParse(remapLineStr, out lineIdx))
											remapLine = lineIdx;
									}
									if (remapLine != -1)
										break;
								}
							}

							//write the new line index at the start of the line
							output.Append(string.Format("({0},", remapLine + 1));
						}
						else
							output.Append("(0,");

						output.AppendLine(line.Substring(number.Length + 3));
					}
					else
						output.Append(line);
				}

				//write the previous error out, if it exists
				if (output.Length > 0)
					errorList.Add(output.ToString());

				return errorList.ToArray();
			}
			catch (CompileException ex)
			{
				compileException = ex;
			}
			catch
			{
				return null;
			}

			if (compileException != null)
				throw compileException;
			return null;
		}
		public static byte[] Generate(SourceShader source, HlslTechnique technique, Platform platform)
		{

		//	ShaderExtensionGenerator exGen = new ShaderExtensionGenerator(source, platform);

			TokenRename vsRename, psRename;
			TokenRename vsBlendRename, vsInstanceRename;

			vsRename = new TokenRename(source, platform, "VS");
			psRename = new TokenRename(source, platform, "PS");

			vsBlendRename = new TokenRename(source, platform, "VS_B");
			vsInstanceRename = new TokenRename(source, platform, "VS_I");

			HlslMethod methodVS = source.GetMethod(technique.VertexShaderMethodName, platform);
			HlslMethod methodPS = source.GetMethod(technique.PixelShaderMethodName, platform);
			
			HlslMethod methodBlending = source.GetMethod(technique.BlendingShaderMethodName, platform);
			HlslMethod methodInstancing = source.GetMethod(technique.InstancingShaderMethodName, platform);

			if (methodPS == null || methodVS == null)
				return null;

			string vsPrefix, psPrefix;

			AsmTechnique asmTechnique = source.GetAsmTechnique(technique.Name, platform);
			vsPrefix = BuildMapping(asmTechnique, "vs", asmTechnique.VertexShader.RegisterSet);
			psPrefix = BuildMapping(asmTechnique, "ps", asmTechnique.PixelShader.RegisterSet);

			string blendingPrefix = null, instancingPrefix = null;
			if (asmTechnique.BlendingShader != null)
				blendingPrefix = BuildMapping(asmTechnique, "vsb", asmTechnique.BlendingShader.RegisterSet);
			if (asmTechnique.InstancingShader != null)
				instancingPrefix = BuildMapping(asmTechnique, "vsi", asmTechnique.InstancingShader.RegisterSet);

			//build the method bodies for the technique

			//process through all the methods used.
			vsRename.methodList.Add(methodVS);
			psRename.methodList.Add(methodPS);

			if (methodBlending != null) vsBlendRename.methodList.Add(methodBlending);
			if (methodInstancing != null) vsInstanceRename.methodList.Add(methodInstancing);

			//setup remapping for registers used
			MapRegistersToRenamer(vsRename, asmTechnique.VertexShader.RegisterSet, "vs");
			MapRegistersToRenamer(psRename, asmTechnique.PixelShader.RegisterSet, "ps");

			if (asmTechnique.BlendingShader != null)
			{
				MapRegistersToRenamer(vsBlendRename, asmTechnique.VertexShader.RegisterSet, "vs");
				MapRegistersToRenamer(vsBlendRename, asmTechnique.BlendingShader.RegisterSet, "vsb");
			}
			if (asmTechnique.InstancingShader != null)
			{
				MapRegistersToRenamer(vsInstanceRename, asmTechnique.VertexShader.RegisterSet, "vs");
				MapRegistersToRenamer(vsInstanceRename, asmTechnique.InstancingShader.RegisterSet, "vsi");
			}

			//finally, parse all the registers used by the Effect. Dump them in as 'unused'
			RegisterSet decompiledEffectRegisters = source.GetDecompiledEffect(platform).EffectRegisters;

			string unusedSamplerName = "__unused_sampler";
			string unusedFloatName = "__unused_";
			string unusedMatrixName = "__unused4x4_";
			string unusedArrayName = "__unused_array";

			foreach (Register reg in decompiledEffectRegisters)
			{
				if (reg.Name == null || reg.Category == RegisterCategory.Texture)
					continue;
				if (reg.Category == RegisterCategory.Sampler)
				{
					vsRename.unusedRemapping.Add(reg.Name, unusedSamplerName);
					psRename.unusedRemapping.Add(reg.Name, unusedSamplerName);
					vsBlendRename.unusedRemapping.Add(reg.Name, unusedSamplerName);
					vsInstanceRename.unusedRemapping.Add(reg.Name, unusedSamplerName);
				}
				else
				{
					vsRename.unusedRemapping.Add(reg.Name, reg.ArraySize > 0 ? unusedArrayName : (reg.Size > 1 ? unusedMatrixName : unusedFloatName));
					psRename.unusedRemapping.Add(reg.Name, reg.ArraySize > 0 ? unusedArrayName : (reg.Size > 1 ? unusedMatrixName : unusedFloatName));
					vsBlendRename.unusedRemapping.Add(reg.Name, reg.ArraySize > 0 ? unusedArrayName : (reg.Size > 1 ? unusedMatrixName : unusedFloatName));
					vsInstanceRename.unusedRemapping.Add(reg.Name, reg.ArraySize > 0 ? unusedArrayName : (reg.Size > 1 ? unusedMatrixName : unusedFloatName));
				}
			}
			//will write booleans down if the values are used.
			vsRename.unusedAccessed = new Dictionary<string, bool>();
			psRename.unusedAccessed = vsRename.unusedAccessed;
			vsBlendRename.unusedAccessed = vsRename.unusedAccessed;
			vsInstanceRename.unusedAccessed = vsRename.unusedAccessed;


			//note, the method list will be added to as new methods are needed by the base method.
			StringBuilder sb = new StringBuilder();

			//extract PS methods
			ExtractMethodBodies(sb, psRename);

			//extract VS methods
			ExtractMethodBodies(sb, vsRename);

			ExtractMethodBodies(sb, vsBlendRename);
			ExtractMethodBodies(sb, vsInstanceRename);

			string techniqueVsName = GetTechniqueInvoke(vsRename, sb, methodVS, technique.VertexShaderArgs);
			string techniquePsName = GetTechniqueInvoke(psRename, sb, methodPS, technique.PixelShaderArgs);

			string techniqueBlendingName = null, techniqueInstancingName = null;

			if (asmTechnique.BlendingShader != null)
				techniqueBlendingName = GetTechniqueInvoke(vsBlendRename, sb, methodBlending, technique.BlendingShaderArgs);
			if (asmTechnique.InstancingShader != null)
				techniqueInstancingName = GetTechniqueInvoke(vsInstanceRename, sb, methodInstancing, technique.InstancingShaderArgs);

			StringBuilder constants = new StringBuilder();

			//work out if any unused values were touched...
			//if so, add them.
			bool addUnusedSampler = false;
			bool addUnusedFloat = false;

			foreach (KeyValuePair<string,bool> item in vsRename.unusedAccessed)
			{
				if (item.Value)
				{
					//something has been used unexpectadly.
					Register reg;
					if (decompiledEffectRegisters.TryGetRegister(item.Key,out reg))
					{
						if (reg.Category == RegisterCategory.Sampler)
							addUnusedSampler = true;
						else
							addUnusedFloat = true;
					}
				}
			}
			if (addUnusedSampler)
				constants.AppendLine("sampler " + unusedSamplerName + ";");
			if (addUnusedFloat)
			{
				constants.AppendLine("const static float4 " + unusedFloatName + " = 0;");
				constants.AppendLine("const static float4x4 " + unusedMatrixName + " = 0;");
				constants.AppendLine("#define " + unusedArrayName + "(__INDEX__) " + unusedFloatName);
			}


			//setup the VS/PS constants
			asmTechnique.ConstructTechniqueConstants(constants, true);

			constants.Append(vsPrefix);
			constants.Append(psPrefix);
			if (blendingPrefix != null) constants.Append(blendingPrefix);
			if (instancingPrefix != null) constants.Append(instancingPrefix);

			constants.AppendLine(ExtractFixedDeclarations(source.HlslShader));

			//finally, build the technique delcaration
			string techniqueStructure =
@"{2}
{3}
technique Shader
{0}
	pass
	{0}
		VertexShader = compile {4} {5};
		PixelShader  = compile {6} {7};
	{1}
{8}{9}{1}";

			string extensionPass =
@"	pass {2}
	{0}
		VertexShader = compile {3} {4};
		PixelShader  = compile {5} {6};
	{1}
";
			string blendExtension = "", instanceExtension = "";

			if (asmTechnique.BlendingShader != null)
			{
				blendExtension = string.Format(extensionPass, "{", "}", "Blending", technique.GetVertexShaderVersion(platform), techniqueBlendingName, technique.GetPixelShaderVersion(platform), techniquePsName);
			}
			if (asmTechnique.InstancingShader != null)
			{
				instanceExtension = string.Format(extensionPass, "{", "}", "Instancing", "vs_3_0", techniqueInstancingName, "ps_3_0", techniquePsName);
			}

			string techniqueSource = string.Format(techniqueStructure, "{", "}", constants, sb,
				technique.GetVertexShaderVersion(platform), techniqueVsName,
				technique.GetPixelShaderVersion(platform), techniquePsName,
				blendExtension,instanceExtension);

			var types = typeof(EffectCompiler).Assembly.GetType("Xen.Graphics.ShaderSystem.EffectCompiler");
			var method = types.GetMethod("CompileEffect");

			CompileEffect effect = Delegate.CreateDelegate(typeof(CompileEffect), types.GetMethod("CompileEffect")) as CompileEffect;

			string compileErrors;
			byte[] compiledEffect = EffectCompiler.CompileEffect(techniqueSource, source.FileName, platform == Platform.Xbox, out compileErrors);

			if (compileErrors != null)
			{
				string[] errors = SanitizeConversionErrorMessage(compileErrors, techniqueSource, source.ShaderSource, source);

				if (source.ManualExtensions == false)
				{
					string errorsLine = "";
					foreach (var error in errors)
						errorsLine += error + Environment.NewLine;

					//error occured in generated code!
					ShaderExtensionGenerator.ThrowGeneratorError(errorsLine.Trim(), source.FileName);
				}
				else
				{
					string header = "XenFX Platform Technique Extraction Failed:";

					if (errors == null)
						Common.ThrowError(header, compileErrors);
					else
						Common.ThrowError(header, errors);
				}
			}

			return compiledEffect;
		}
		private void BuildTechniqueMethod(SourceShader shader, ShaderExtension extension)
		{
			methodExtractionExtension = extension;

			foreach (var method in methodList)
			{
				if (methodBuilt.ContainsKey(method.Name) == false)
					methodBuilt.Add(method.Name, false);
			}

			foreach (var tech in shader.GetAllTechniques())
			{
				BuildMethod(tech.VertexShaderMethodName, extension);
			}

			methodBuilt.Clear();

			UnwindBackup(shader.HlslShader);
		}
		private ShaderExtensionGenerator(SourceShader shader, Platform platform, string techniquePostfix)
		{
			this.techniquePostfix = techniquePostfix;

			//this method temporary modifies the HlslStructure stored in the source shader, so take a backup first.
			structureBackup = new Dictionary<HlslStructure, HlslStructure.ShaderStatement[]>();
			BackupStructure(shader.HlslShader);
			

			RegisterSet registers     = shader.GetDecompiledEffect(platform).EffectRegisters;

			List<string> addRegisters = new List<string>();

			methodList = shader.GetAllMethods(platform, true).ToArray();

			foreach (var method in methodList)
			{
				if (methodNames.ContainsKey(method.Name))
					continue;

				bool open = false;
				bool args = false;

				//work out if this method takes args
				foreach (var element in method.HlslShader.Elements)
				{
					if (open)
					{
						if (element == ")")
							open = false;
						else
							args = true;
					}
					if (element == "(")
						open = true;
				}

				methodNames.Add(method.Name,args);
			}

			//collect up the declared world matrices
			foreach (var reg in registers)
			{
				if (reg.Semantic != null && reg.Semantic.StartsWith("WORLD", StringComparison.InvariantCultureIgnoreCase))
				{
					string replaceWith = reg.Semantic.Substring(5);

					//see if the replacement exists.
					if (replaceWith.Length > 0)
					{
						bool createReg = true;

						foreach (var r2 in registers)
						{
							if (r2.Semantic != null && r2.Semantic.Equals(replaceWith, StringComparison.InvariantCultureIgnoreCase))
							{
								createReg = false;
								matrixRemap.Add(reg.Name, new MatrixMapping() { Name = reg.Name, RemapTo = r2.Name + worldMatrixName, BaseName  = r2.Name});
							}
						}

						if (createReg)
						{
							addRegisters.Add(replaceWith);
							matrixRemap.Add(reg.Name, new MatrixMapping() { Name = reg.Name, RemapTo = ToInternalMatrixName(reg.Name), BaseName = ToInternalMatrixName(replaceWith) }); 
						}
					}
					else
						worldMatrix = reg;
				}
			}

			header.AppendLine();
			header.AppendFormat("float4 {0}[216] : BLENDMATRICES; ", blendMatricesName);
			header.AppendLine();
			//add the new registers
			foreach (var reg in addRegisters)
			{
				header.AppendFormat("float4x4 {0} : {1}; ", ToInternalMatrixName(reg), reg);
				header.AppendLine();
			}

			methodSignatureAppend = "";
			methodCallAppend      = "";

			foreach (var remap in matrixRemap.Values)
			{
				methodSignatureAppend += string.Format("float4x4 {0}, ", remap.RemapTo);
				methodCallAppend      += string.Format("{0}, ", remap.RemapTo);
			}
			methodSignatureAppend += "float4x4 " + worldMatrixName;
			methodCallAppend      += worldMatrixName;

			if (worldMatrix.Name != null)
			{
				matrixRemap.Add(worldMatrix.Name, new MatrixMapping() { Name = worldMatrix.Name, RemapTo = worldMatrixName });
			}


			BuildTechniqueMethod(shader, ShaderExtension.Blending);
			BuildTechniqueMethod(shader, ShaderExtension.Instancing);

			foreach (var tech in shader.GetAllTechniques())
			{
				if (tech.Platform == platform || tech.Platform == Platform.Both)
				{
					AsmTechnique asmTechnique = shader.GetAsmTechnique(tech.Name, platform);
					rootVsMethodName = tech.VertexShaderMethodName;
					GenerateTechnique(shader, tech, asmTechnique, platform);
				}
			}

			header.Append(builtShader);
			header.Append(footer);

			result = header.ToString();
		}
			public TokenRename(SourceShader shader, Platform platform, string extension)
			{
				this.shader = shader;
				this.platform = platform;
				this.extension = extension;
			}
		private string ProcessTechniqueVS(SourceShader shader, HlslTechnique technique, AsmTechnique asmTechnique, ShaderExtension extension, Platform platform)
		{
			HlslMethod vs = shader.GetMethod(technique.VertexShaderMethodName, platform);
			HlslMethod ps = shader.GetMethod(technique.PixelShaderMethodName, platform);

			if (vs == null) throw new CompileException(string.Format("Unabled to find declaration for vertex shader method '{0}'", technique.VertexShaderMethodName));
			if (ps == null) throw new CompileException(string.Format("Unabled to find declaration for pixel shader method '{0}'", technique.PixelShaderMethodName));

			string nameAppend = "_" + Guid.NewGuid().ToString("N") + "_" + extension.ToString();
			string blendName = "__blend_weights__GEN";
			string indicesName = "__blend_indices__GEN";

			//generated merged matrices
			StringBuilder matrixGen = new StringBuilder();
			foreach (var remap in matrixRemap.Values)
			{
				if (remap.BaseName != null) // this will be null for the world matrix
				{
					//find the matching register in the technique
					string matrixType;
					string matrixExpansion = GetMatrixRankExpansion(remap.Name, asmTechnique, out matrixType);

					if (extension == ShaderExtension.Instancing)
						matrixGen.AppendFormat("\tfloat4x4 {0} = float4x4(({4})mul({1},{2}){3});", remap.RemapTo, worldMatrixName, remap.BaseName, matrixExpansion, matrixType);
					if (extension == ShaderExtension.Blending)
						matrixGen.AppendFormat("\tfloat4x4 {0} = float4x4(({4})mul({1},{2}){3});", remap.RemapTo, worldMatrixName, remap.Name, matrixExpansion, matrixType);
					matrixGen.AppendLine();
				}
			}


			//create the method signatures
			footer.AppendLine();
			bool multiArg = false;
			StringBuilder argList = new StringBuilder();
			int argIndex = -1;
			bool transposeWorldMatrix = false;

			foreach (var element in vs.HlslShader.Elements)
			{
				if (element.Statement == vs.Name)
				{
					footer.Append(vs.Name);
					footer.Append(nameAppend);
				}
				else
				{
					if (element.Statement == "(" || element.Statement == ",")
						argIndex = 0;
					else
					{
						argIndex++;
						if (element.Statement == "out" ||
							element.Statement == "in" ||
							element.Statement == "inout" ||
							element.Statement == "uniform" ||
							element.Statement == "const")
							argIndex--;
						if (argIndex != -1 && argIndex == 2)
						{
							if (argList.Length > 0)
								argList.Append(", ");
							argList.Append(element.Statement);
						}
					}

					if (element.Statement == ")")
					{
						argIndex = -1;

						if (methodNames.TryGetValue(vs.Name, out multiArg) && multiArg)
							footer.Append(", ");

						if (extension == ShaderExtension.Instancing)
						{
							footer.Append("float4x4 " + worldMatrixName + "_transpose : POSITION12");
							transposeWorldMatrix = true;
						}
						if (extension == ShaderExtension.Blending)
						{
							footer.AppendFormat("float4 {0} : BLENDWEIGHT, int4 {1} : BLENDINDICES", blendName, indicesName);
						}
					}

					footer.Append(element);
					footer.Append(' ');
				}
			}
			footer.AppendLine();
			footer.AppendLine("{");

			if (transposeWorldMatrix)
			{
				footer.AppendLine("\tfloat4x4 " + worldMatrixName + " = transpose(" + worldMatrixName + "_transpose);");
			}

			if (extension == ShaderExtension.Blending)
			{
				string calculation =
@"	float4x4 {3}
		= transpose(float4x4(
			{0}[{1}.x * 3 + 0] * {2}.x + {0}[{1}.y * 3 + 0] * {2}.y + {0}[{1}.z * 3 + 0] * {2}.z + {0}[{1}.w * 3 + 0] * {2}.w,
			{0}[{1}.x * 3 + 1] * {2}.x + {0}[{1}.y * 3 + 1] * {2}.y + {0}[{1}.z * 3 + 1] * {2}.z + {0}[{1}.w * 3 + 1] * {2}.w,
			{0}[{1}.x * 3 + 2] * {2}.x + {0}[{1}.y * 3 + 2] * {2}.y + {0}[{1}.z * 3 + 2] * {2}.z + {0}[{1}.w * 3 + 2] * {2}.w,
			float4(0,0,0,1)));";

				footer.AppendFormat(calculation, blendMatricesName, indicesName, blendName, worldMatrixName);
				footer.AppendLine();
			}
			
			footer.Append(matrixGen);
			
			footer.AppendFormat("\t{4}{0}({1}{2}{3});", ToInternalMethodName(vs.Name, extension), methodCallAppend, multiArg ? ", " : "", argList, vs.HasReturnValue ? "return " : "");

			footer.AppendLine();
			footer.AppendLine("}");

			return vs.Name + nameAppend;
		}
		public ShaderDom(SourceShader source, string techniqueName, Platform platform, CompileDirectives directives)
		{
			this.domList = new List<DomBase>();
			this.domList.Add(this);

			//add custom dom's
			this.domList.Add(new ShaderBytes(source, techniqueName, platform));

			//needs to be passed to the registers as an interface provider
			ConstantSetup constantes = new ConstantSetup(source, techniqueName, platform);

			this.domList.Add(new ShaderRegisters(source, techniqueName, platform, constantes));
			this.domList.Add(constantes);
			this.domList.Add(new ShaderTextures(source, techniqueName, platform));

			foreach (DomBase dom in domList)
				dom.Setup(this);

			this.techniqueName = techniqueName;
			this.source = source;
			this.platform = platform;


			classDom = new CodeTypeDeclaration(techniqueName);
			classDom.IsClass = true;
			classDom.Attributes = MemberAttributes.Final | MemberAttributes.Public;
			classDom.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.Public | TypeAttributes.Class;


			//provide a useful comment to the class
			GenerateClassComment();


			if (source.GenerateInternalClass)
			{
				classDom.Attributes = MemberAttributes.Final | MemberAttributes.Assembly;
				classDom.TypeAttributes = TypeAttributes.NestedAssembly | TypeAttributes.Class | TypeAttributes.Sealed;
			}
			
			classDom.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.Diagnostics.DebuggerStepThroughAttribute))));
			classDom.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.CodeDom.Compiler.GeneratedCodeAttribute)),new CodeAttributeArgument(new CodePrimitiveExpression(GetType().Assembly.ManifestModule.Name)),new CodeAttributeArgument(new CodePrimitiveExpression(GetType().Assembly.ManifestModule.ModuleVersionId.ToString()))));

			classDom.BaseTypes.Add(new CodeTypeReference(typeof(BaseShader)));

			//add custom base types to the shader
			//these are defined in TechniqueExtraData
			AsmTechnique asmTechnique = this.source.GetAsmTechnique(this.techniqueName, this.platform);

			if (asmTechnique.TechniqueExtraData != null && asmTechnique.TechniqueExtraData.ClassBaseTypes != null)
			{
				foreach (string baseTypeName in asmTechnique.TechniqueExtraData.ClassBaseTypes)
					classDom.BaseTypes.Add(new CodeTypeReference(baseTypeName));
			}


			this.directives = directives;

			SetupMembers(techniqueName);
			foreach (DomBase dom in domList)
				dom.SetupMembers(this);

			CreateConstructor();
			CreateStaticGraphicsInitMethod();
			CreateBindMethod();

			CreateWarmShaderMethod();

			CreateChangedMethod();

			CreateVertexInputMethods();

			CodeTypeMemberCollection pcMembers = new CodeTypeMemberCollection();
			CodeTypeMemberCollection xboxMembers = new CodeTypeMemberCollection();

			foreach (DomBase dom in this.domList)
			{
				dom.AddMembers(this, delegate(CodeTypeMember s, string c) { Comment(s, c); classDom.Members.Add(s); }, Platform.Both);

				if (!source.DefinePlatform) // no need for specialization when the platform is constant
				{
					dom.AddMembers(this, delegate(CodeTypeMember s, string c) { Comment(s, c); pcMembers.Add(s); }, Platform.Windows);
					dom.AddMembers(this, delegate(CodeTypeMember s, string c) { Comment(s, c); xboxMembers.Add(s); }, Platform.Xbox);
				}
			}


			foreach (DomBase dom in this.domList)
			{
				dom.AddReadonlyMembers(this, 
					delegate(CodeTypeMember s, string c)
					{
						CodeTypeMember readonlySnip = directives.CreateReadOnlySnippet();
						Comment(readonlySnip ?? s, c);
						if (readonlySnip != null) classDom.Members.Add(readonlySnip);
						classDom.Members.Add(s); 
					}, Platform.Both);

				if (!source.DefinePlatform)
				{
					dom.AddReadonlyMembers(this,
						delegate(CodeTypeMember s, string c)
						{
							CodeTypeMember readonlySnip = directives.CreateReadOnlySnippet();
							Comment(readonlySnip ?? s, c);
							if (readonlySnip != null) pcMembers.Add(readonlySnip);
							pcMembers.Add(s);
						}, Platform.Windows);

					dom.AddReadonlyMembers(this,
						delegate(CodeTypeMember s, string c)
						{
							CodeTypeMember readonlySnip = directives.CreateReadOnlySnippet();
							Comment(readonlySnip ?? s, c);
							if (readonlySnip != null) xboxMembers.Add(readonlySnip);
							xboxMembers.Add(s);
						}, Platform.Xbox);
				}
			}

			if (pcMembers.Count > 0 || xboxMembers.Count > 0)
			{
				//add #if / else blocks

				classDom.Members.Add(directives.IfXboxStatement);

				foreach (CodeTypeMember type in xboxMembers)
					classDom.Members.Add(type);

				classDom.Members.Add(directives.ElseStatement);

				foreach (CodeTypeMember type in pcMembers)
					classDom.Members.Add(type);

				classDom.Members.Add(directives.EndifStatement);
			}

			//finally, create the attribute setters

			CreateSetAttributeMethod(typeof(float), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(Vector2), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(Vector3), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(Vector4), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(Matrix), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(bool), "SetAttributeImpl", "attribute");

			CreateSetAttributeMethod(typeof(float[]), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(Vector2[]), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(Vector3[]), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(Vector4[]), "SetAttributeImpl", "attribute");
			CreateSetAttributeMethod(typeof(Matrix[]), "SetAttributeImpl", "attribute");

			CreateSetAttributeMethod(typeof(Xen.Graphics.TextureSamplerState), "SetSamplerStateImpl", "sampler");
			CreateSetAttributeMethod(typeof(Texture), "SetTextureImpl", "texture");
			CreateSetAttributeMethod(typeof(Texture2D), "SetTextureImpl", "texture");
			CreateSetAttributeMethod(typeof(Texture3D), "SetTextureImpl", "texture");
			CreateSetAttributeMethod(typeof(TextureCube), "SetTextureImpl", "texture");

		}
		public static string Process(SourceShader shader)
		{
			return new TechniqueRemover(shader).result.ToString();
		}
Beispiel #28
0
        //this is a bit of a hack.
        //it relies on the fact that the DirectX shader compiler
        //marks up the disasembled shader with comments detailing the shader inputs.
        public static AsmTechnique[] ExtractTechniques(SourceShader shader, Platform platform)
        {
            //decompile the shader
            DecompiledEffect fx = new DecompiledEffect(shader, platform);

            //break it up into techniques
            Tokenizer assemblyTokens = new Tokenizer(fx.DecompiledAsm, false, true, true);

            List <AsmTechnique> techniqes = new List <AsmTechnique>();

            while (assemblyTokens.NextToken())
            {
                if (assemblyTokens.Token.Equals("technique", StringComparison.InvariantCultureIgnoreCase))
                {
                    //should be format:
                    //technique NAME
                    //{
                    //}

                    assemblyTokens.NextToken();
                    string name = assemblyTokens.Token;

                    assemblyTokens.NextToken();

                    //may be a line break
                    if (assemblyTokens.Token.Trim().Length == 0)
                    {
                        assemblyTokens.NextToken();
                    }

                    //should be a {
                    if (assemblyTokens.Token != "{")
                    {
                        throw new CompileException("Unexpected token in assembly technique declaration, expected '{': " + assemblyTokens.Token);
                    }

                    // read the entire technique {} block
                    if (!assemblyTokens.ReadBlock())
                    {
                        throw new CompileException("Unexpected end of string in assembly technique pass declaration");
                    }

                    AsmTechnique asm = new AsmTechnique(name, assemblyTokens.Token, fx.GetTechniqueDefaultValues(name));

                    if (!shader.SkipConstantValidation)
                    {
                        //do some extra validation to make sure pixel inputs match vertex outputs
                        asm.ValidatePixleShaderInput(shader, platform);
                    }

                    techniqes.Add(asm);
                }
            }

            for (int i = 0; i < techniqes.Count; i++)
            {
                techniqes[i].MergeSemantics(fx.EffectRegisters);
            }

            return(techniqes.ToArray());
        }
		public ShaderTextures(SourceShader source, string techniqueName, Platform platform)
		{
			this.psSamplers = new List<Register>();
			this.vsSamplers = new List<Register>();
			this.allSamplers = new Dictionary<string, SharedSampler>();

			AsmTechnique technique = source.GetAsmTechnique(techniqueName, platform);
			TechniqueExtraData extras = technique.TechniqueExtraData;

			//pull out the textures that will be used
			textures = new TextureAssociation[extras.TechniqueTextures.Length];
			for (int i = 0; i < extras.TechniqueTextures.Length; i++)
				textures[i] = new TextureAssociation(extras.TechniqueTextures[i]);

			//now do the samplers
			RegisterSet set = technique.PixelShader.RegisterSet;

			//pixel first
			foreach (Register reg in set)
			{
				if (reg.Category == RegisterCategory.Sampler)
				{
					psSamplers.Add(reg);

					int textureIndex = extras.PixelSamplerTextureIndex[reg.Index];

					if (textureIndex == -1)
						ThrowSamplerNoTextureException(reg);

					textures[textureIndex].PsSamplers.Add(reg.Index);

					//add the sampler to 'allSamplers'
					SharedSampler ss = new SharedSampler();
					ss.PsIndex = reg.Index;
					ss.SamplerDetails = reg;
					ss.Index = allSamplers.Count;
					ss.DefaultState = extras.PixelSamplerStates[reg.Index];
					allSamplers.Add(reg.Name, ss);
				}
			}

			set = technique.VertexShader.RegisterSet;

			//now vertex
			foreach (Register reg in set)
			{
				if (reg.Category == RegisterCategory.Sampler)
				{
					vsSamplers.Add(reg);

					int textureIndex = extras.VertexSamplerTextureIndex[reg.Index];
					if (textureIndex == -1)
						ThrowSamplerNoTextureException(reg);

					textures[textureIndex].VsSamplers.Add(reg.Index);

					//add the sampler to 'allSamplers'
					SharedSampler ss;
					if (!allSamplers.TryGetValue(reg.Name, out ss))
					{
						ss = new SharedSampler();
						ss.SamplerDetails = reg;
						ss.Index = allSamplers.Count;
						ss.DefaultState = extras.VertexSamplerStates[reg.Index];
						allSamplers.Add(reg.Name, ss);
					}
					ss.VsIndex = reg.Index;
				}
			}
		}