コード例 #1
0
		private HlslStructure(ShaderStatement[] el, HlslStructure[] ch, bool braceEnclosed, bool bracketEnclosedChildren)
		{
			this.Elements = el;
			this.Children = ch;
			this.BraceEnclosedChildren = braceEnclosed;
			this.BracketEnclosedChildren = bracketEnclosedChildren;
		}
コード例 #2
0
        //extracts the techniques
        internal HlslMethod(HlslStructure hs, Platform platform)
        {
            this.hs       = hs;
            this.platform = platform;

            for (int i = 1; i < hs.Elements.Length; i++)
            {
                if (hs.Elements[i] == "(")
                {
                    name = hs.Elements[i - 1];
                }
            }

            foreach (HlslStructure child in hs.GetEnumerator())
            {
                if (child != hs)
                {
                    for (int i = 0; i < child.Elements.Length - 1; i++)
                    {
                        if (child.Elements[i] == VFetchIncludeHandler.IncludeSymbol && child.Elements[i + 1] == "(")
                        {
                            usesVFetch = true;
                        }
                    }
                    if (usesVFetch)
                    {
                        break;
                    }
                }
            }
        }
コード例 #3
0
        public SourceShader(string shaderSource, string filename, bool extractAsmTechniques)
        {
            this.shaderSource = shaderSource;
            this.filename     = filename;
            this.sourceLines  = shaderSource.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

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

            this.techniques = new List <HlslTechnique>();
            this.methods    = new List <HlslMethod>();

            this.hlslShader     = new HlslStructure(shaderSource);
            this.includedSource = new List <SourceShader>();

            if (sourceLines.Length > 0)
            {
                this.compilerOptions = ComputeCompilerOps(sourceLines[0], out internalClass, out poolShaderBytes, out useParentNamespace, out mixedMode, out debugHlslProcessXboxShader, out skipConstantValidation);
                ComputeClassExtensions(sourceLines[0], this.shaderExtensions);
            }
            if (sourceLines.Length > 1)
            {
                ComputeClassExtensions(sourceLines[1], this.shaderExtensions);
            }

            if (poolShaderBytes)
            {
                this.bytePoolPc   = new Dom.BytePool();
                this.bytePoolXbox = new Dom.BytePool();
            }

            this.ExtractIncludeSource(ref this.useVfetch);

            this.mixedMode &= !this.useVfetch;

            this.ExtractMethods();


            asmTechniques = new List <AsmTechnique>();
            if (!mixedMode)
            {
                xboxAsmTechniques = new List <AsmTechnique>();
            }

            if (extractAsmTechniques)
            {
                this.ExtractAsmTechniques();
            }
        }
コード例 #4
0
        //extracts the techniques
        internal HlslTechnique(HlslStructure hs, Platform platform)
        {
            this.hs       = hs;
            this.platform = platform;
            this.name     = hs.Elements[1];

            //first child should be the first pass
            for (int i = 0; i < hs.Children.Length; i++)
            {
                if (hs.Children[i].Elements.Length > 0 &&
                    hs.Children[i].Elements[0] == "pass")
                {
                    //good.

                    ExtractPass(hs.Children[i], out pixelShaderMethodName, out vertexShaderMethodName, out psVersion, out vsVersion, out psArgs, out vsArgs);
                    break;
                }
            }
        }
コード例 #5
0
		private SourceShader(string shaderSource, string filename, string generatedAppend)
		{
			this.sourceLines = shaderSource.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

			if (sourceLines.Length > 0)
			{
				ComputeCompilerOps(sourceLines[0], out internalClass, out useParentNamespace, out mixedMode, out debugHlslProcessXboxShader, out skipConstantValidation, out exposeRegisters, out manualExtensions);
			}

			this.shaderSource = shaderSource;
			this.filename = filename;

			this.techniques = new List<HlslTechnique>();
			this.methods = new List<HlslMethod>();
			this.hlslShader = new HlslStructure(shaderSource);
			this.includedSource = new List<SourceShader>();
		
			this.ExtractIncludeSource();
			this.ExtractMethods(generatedAppend);

			asmTechniques = new List<AsmTechnique>();
			if (!mixedMode) xboxAsmTechniques = new List<AsmTechnique>();
		}
コード例 #6
0
		void TranslateMatrices(HlslStructure.ShaderStatement[] elements, int callDepth, ShaderExtension extension)
		{
			bool isInstancing = extension == ShaderExtension.Instancing;
			List<int> skipFinalRemappingIndices = new List<int>();

			int processingMul = 0, depth = 0, arg = 0;
			int argStart = 0, argEnd = 0;
			int remapArg = -1;
			int remapIndex = 0;
			MatrixMapping remapping = new MatrixMapping();

			Stack<int> mulStart = new Stack<int>();
			Stack<int> mulDepth = new Stack<int>();
			Stack<int> mulArg = new Stack<int>();
			Stack<int> mulArgStart = new Stack<int>();
			Stack<int> mulArgEnd = new Stack<int>();
			Stack<int> mulRemap = new Stack<int>();
			Stack<int> mulRemapIdx = new Stack<int>();
			Stack<MatrixMapping> mulRemapping = new Stack<MatrixMapping>();

			for (int i = 0; i < elements.Length; i++)
			{
				string line = elements[i].Statement;

				if (line == "mul")
				{
					processingMul++;
					mulStart.Push(i);
					mulDepth.Push(depth);
					mulArg.Push(arg);
					mulArgEnd.Push(argEnd);
					mulArgStart.Push(argStart);
					mulRemap.Push(remapArg);
					mulRemapping.Push(remapping);
					mulRemapIdx.Push(remapIndex);

					depth = 0;
					arg = 0;
					argStart = 0;
					argEnd = 0;
					remapArg = -1;
					remapIndex = 0;
					remapping = new MatrixMapping();
				}

				MatrixMapping mapping;
				if (processingMul > 0 && depth == 1 && matrixRemap.TryGetValue(line, out mapping) && (mapping.BaseName != null || !isInstancing))
				{
					remapArg = arg;
					remapping = mapping;
					remapIndex = i;
				}

				if (processingMul > 0 && line == "(")
				{
					if (depth == 0)
						argStart = i;
					depth++;
				}

				if (processingMul > 0 && depth == 1 && line == ",")
				{
					if (depth == 1)
						argEnd = i;
					arg++;
				}

				if (processingMul > 0 && line == ")")
				{
					depth--;
					if (depth == 0)
					{
						string baseMatrix = remapping.Name;
						if (isInstancing)
							baseMatrix = remapping.BaseName;

						string prefix = "";
						int startPrefix = -1;
						if (remapArg == 1)
							startPrefix = argEnd;
						if (remapArg == 0)
							startPrefix = argStart;

						if (remapIndex > startPrefix && startPrefix != -1)
						{
							for (int p = startPrefix + 1; p < remapIndex; p++)
								prefix += elements[p].Statement + " ";
						}

						//right, see if the args need modifying.
						if (remapArg == 1)
						{
							//a known remapping matrix was used.
							var element = elements[remapIndex];
							elements[remapIndex] = new HlslStructure.ShaderStatement(baseMatrix, element.Line);

							element = elements[argStart];
							elements[argStart] = new HlslStructure.ShaderStatement("(mul(", element.Line);

							element = elements[argEnd];
							elements[argEnd] = new HlslStructure.ShaderStatement("," + prefix + worldMatrixName + "),", element.Line);

							if (!isInstancing)
								skipFinalRemappingIndices.Add(remapIndex);
						}

						if (remapArg == 0) // transpose
						{
							//a known remapping matrix was used.
							var element = elements[remapIndex];
							elements[remapIndex] = new HlslStructure.ShaderStatement(baseMatrix, element.Line);

							element = elements[argEnd];
							elements[argEnd] = new HlslStructure.ShaderStatement(",mul(" + prefix + worldMatrixName + ",", element.Line);

							element = elements[i];
							elements[i] = new HlslStructure.ShaderStatement("))", element.Line);

							if (!isInstancing)
								skipFinalRemappingIndices.Add(remapIndex);
						}


						processingMul--;
						mulStart.Pop();
						depth = mulDepth.Pop();
						arg = mulArg.Pop();
						argEnd = mulArgEnd.Pop();
						argStart = mulArgStart.Pop();
						remapArg = mulRemap.Pop();
						remapping = mulRemapping.Pop();
						remapIndex = mulRemapIdx.Pop();
					}
				}
			}

			//find unremapped matrices
			if (callDepth > 0)
			{
				for (int i = 0; i < elements.Length; i++)
				{
					//it is intended that this matrix reference is not modified.
					if (!isInstancing && skipFinalRemappingIndices.Contains(i))
						continue;

					MatrixMapping mapping;
					if (matrixRemap.TryGetValue(elements[i].Statement, out mapping))
						elements[i] = new HlslStructure.ShaderStatement(mapping.RemapTo, elements[i].Line);
				}
			}
		}
コード例 #7
0
			bool HlslStructure.ITokenTranslator.IncludeBlock(HlslStructure block, int depth)
			{
				return true;
			}
コード例 #8
0
		private static string ExtractFixedDeclarations(HlslStructure shader)
		{
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < shader.Children.Length; i++)
			{
				if (shader.Children[i].Elements.Length > 0 &&
					(shader.Children[i].Elements[0] == "struct" ||
					shader.Children[i].Elements[0] == "static"))
				{
					sb.Append(shader.Children[i].ToString());
					sb.AppendLine(";");
				}
			}
			return sb.ToString();
		}
コード例 #9
0
			public bool IncludeBlock(HlslStructure block, int depth) { return true; }
コード例 #10
0
		private static void ExtractPass(HlslStructure pass, out string ps, out string vs, out string psVersion, out string vsVersion, out string[] psArgs, out string[] vsArgs)
		{
			ps = vs = vsVersion = psVersion = null;
			psArgs = vsArgs = null;

			//a bit nasty...
			foreach (HlslStructure hs in pass.Children)
			{
				//should be:
				//
				//VertexShader = compile vs_2_0 Zomg(true!);
				//
				//or similar

				int type = -1;
				string target = null, method = null;
				List<string> args = new List<string>();
				int paranethDepth = 0;

				for (int i = 0; i < hs.Elements.Length; i++)
				{
					if (hs.Elements[i].Statement.Equals("VertexShader", StringComparison.InvariantCultureIgnoreCase))
						type = 1;
					if (hs.Elements[i].Statement.Equals("PixelShader", StringComparison.InvariantCultureIgnoreCase))
						type = 2;

					if (hs.Elements[i].Statement.Equals("compile", StringComparison.InvariantCultureIgnoreCase))
						target = hs.Elements[i + 1];

					if (hs.Elements[i] == ")")
					{
						paranethDepth--;
					}

					if (paranethDepth > 0)
						args.Add(hs.Elements[i]);

					if (hs.Elements[i] == "(")
					{
						if (paranethDepth == 0)
							method = hs.Elements[i - 1];
						paranethDepth++;
					}
				}

				if (type == 1)
				{
					vs = method;
					vsArgs = args.ToArray();
					vsVersion = target;
				}
				if (type == 2)
				{
					ps = method;
					psArgs = args.ToArray();
					psVersion = target;
				}
			}
		}
コード例 #11
0
		//extracts the techniques
		internal HlslTechnique(HlslStructure hs, Platform platform, string generatedPrefix)
		{
			this.hs = hs;
			this.platform = platform;
			this.name = hs.Elements[1];
			bool primaryPassSet = false;

			if (generatedPrefix != null)
			{
				if (name.EndsWith(generatedPrefix))
				{
					name = name.Substring(0, name.Length - generatedPrefix.Length);
					IsGenerated = true;
				}
			}

			//first child should be the first pass
			for (int i = 0; i < hs.Children.Length; i++)
			{
				if (hs.Children[i].Elements.Length > 0 && 
					hs.Children[i].Elements[0] == "pass")
				{
					//good.

					//this could be an animation or blending pass
					bool isAnimation = false, isInstancing = false;
					if (hs.Children[i].Elements.Length > 1)
						AsmTechnique.ExtractPassType(hs.Children[i].Elements[1], out isAnimation, out isInstancing);

					if (isAnimation || isInstancing)
					{
						string ignored, vs_version, name;
						string[] args_ignored, args;
						ExtractPass(hs.Children[i], out ignored, out name, out ignored, out vs_version, out args_ignored, out args);
					//	if (vs_version != vsVersion)
					//		throw new CompileException(string.Format("Technique Extension Pass '{0}' cannot use a different vertex shader version", hs.Children[i].Elements[1]));
						if (isInstancing)
						{
							instancingShaderMethodName = name;
							instancingArgs = args;
						}
						else
						{
							blendingShaderMethodName = name;
							blendArgs = args;
						}
					}
					else if (!primaryPassSet)
					{
						ExtractPass(hs.Children[i], out pixelShaderMethodName, out vertexShaderMethodName, out psVersion, out vsVersion, out psArgs, out vsArgs);
						primaryPassSet = true;
					}
				}
			}
		}
コード例 #12
0
		//extracts the techniques
		internal HlslMethod(HlslStructure hs, Platform platform)
		{
			this.hs = hs;
			this.platform = platform;

			for (int i = 1; i < hs.Elements.Length; i++)
			{
				if (hs.Elements[i] == "(")
					name = hs.Elements[i - 1];
			}
		}
コード例 #13
0
        private static void ExtractPass(HlslStructure pass, out string ps, out string vs, out string psVersion, out string vsVersion, out string[] psArgs, out string[] vsArgs)
        {
            ps     = vs = vsVersion = psVersion = null;
            psArgs = vsArgs = null;

            //a bit nasty...
            foreach (HlslStructure hs in pass.Children)
            {
                //should be:
                //
                //VertexShader = compile vs_2_0 Zomg(true!);
                //
                //or similar

                int           type = -1;
                string        target = null, method = null;
                List <string> args          = new List <string>();
                int           paranethDepth = 0;

                for (int i = 0; i < hs.Elements.Length; i++)
                {
                    if (hs.Elements[i].Equals("VertexShader", StringComparison.InvariantCultureIgnoreCase))
                    {
                        type = 1;
                    }
                    if (hs.Elements[i].Equals("PixelShader", StringComparison.InvariantCultureIgnoreCase))
                    {
                        type = 2;
                    }

                    if (hs.Elements[i].Equals("compile", StringComparison.InvariantCultureIgnoreCase))
                    {
                        target = hs.Elements[i + 1];
                    }

                    if (hs.Elements[i] == ")")
                    {
                        paranethDepth--;
                    }

                    if (paranethDepth > 0)
                    {
                        args.Add(hs.Elements[i]);
                    }

                    if (hs.Elements[i] == "(")
                    {
                        if (paranethDepth == 0)
                        {
                            method = hs.Elements[i - 1];
                        }
                        paranethDepth++;
                    }
                }

                if (type == 1)
                {
                    vs        = method;
                    vsArgs    = args.ToArray();
                    vsVersion = target;
                }
                if (type == 2)
                {
                    ps        = method;
                    psArgs    = args.ToArray();
                    psVersion = target;
                }
            }
        }
コード例 #14
0
		void TranslateMethodNames(HlslStructure.ShaderStatement[] elements, int callDepth, ShaderExtension extension)
		{
			for (int i = 0; i < elements.Length; i++)
			{
				string methodName = elements[i].Statement;

				bool multArg;
				if (methodNames.TryGetValue(methodName, out multArg))
				{
					BuildMethod(methodName, extension);

					//find the method start
					for (int n = i+1; n < elements.Length; n++)
					{
						if (elements[n] == "(")
						{
							string argAppend = multArg ? ", " : "";
							//append the method signatures
							if (callDepth == 0)
								elements[n] = new HlslStructure.ShaderStatement("(" + this.methodSignatureAppend + argAppend, elements[n].Line);
							else
								elements[n] = new HlslStructure.ShaderStatement("(" + this.methodCallAppend + argAppend, elements[n].Line);

							elements[i] = new HlslStructure.ShaderStatement(ToInternalMethodName(methodName,extension), elements[i].Line);
							break;
						}
					}
				}
			}
		}
コード例 #15
0
		bool HlslStructure.ITokenTranslator.IncludeBlock(HlslStructure block, int depth)
		{
			TranslateMatrices(block.Elements, depth, methodExtractionExtension);
			TranslateMethodNames(block.Elements, depth, methodExtractionExtension);

			return true;
		}
コード例 #16
0
		private void UnwindBackup(HlslStructure hlslStructure)
		{
			HlslStructure.ShaderStatement[] elements = structureBackup[hlslStructure];

			for (int i = 0; i < hlslStructure.Elements.Length; i++)
				hlslStructure.Elements[i] = elements[i];

			foreach (var child in hlslStructure.Children)
				UnwindBackup(child);
		}
コード例 #17
0
		private void BackupStructure(HlslStructure hlslStructure)
		{
			structureBackup.Add(hlslStructure, hlslStructure.Elements.Clone() as HlslStructure.ShaderStatement[]);
			foreach (var child in hlslStructure.Children)
				BackupStructure(child);
		}
コード例 #18
0
		public bool IncludeBlock(HlslStructure block, int depth)
		{
			return !techniques.Contains(block);
		}
コード例 #19
0
        private byte[] ProcessMethod(HlslMethod method, IEnumerator <string> argsEnum, ShaderProfile shaderProfile)
        {
            //this is where things get silly... :-)

            //the method uses vfetch, and for various reasons, the shader code cannot be extracted from an Effect
            //the shader also cannot be decompiled.
            //However, a single shader can be compiled from HLSL. Which is great.... except...
            //the technique may define the method to use, and may pass in arguements..
            // like so:
            //
            // VertexShader = compile vs_2_0 zomg(true);
            //
            //In such a case, the method 'zomg' can't be directly compiled using ShaderCompiler.
            //When this is the case, things get stupid.
            //
            //The way to compile the method is to create a stub that calls the real method,
            //with values for the arguements. Modifying the method declaration with default arguements
            //wouldn't always work...

            //this is, of course, assuming the method has uniform arguements being passed in.
            //if it isn't, then no problem.

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

            while (argsEnum.MoveNext())
            {
                rawArgs.Add(argsEnum.Current);
            }

            CompiledShader compiledShader;
            string         workingDirectory = null;

            if (rawArgs.Count == 0)
            {
                //just compile the method directly (easy)...

                try
                {
                    //set the working directory, since it's using CompileFromFile
                    workingDirectory = Directory.GetCurrentDirectory();

                    string path = Path.GetDirectoryName(source.FileName);
                    if (path != null && path.Length > 0)
                    {
                        Directory.SetCurrentDirectory(Path.GetDirectoryName(source.FileName));
                    }

                    compiledShader =
                        ShaderCompiler.CompileFromFile(
                            Path.GetFileName(source.FileName),
                            DecompiledEffect.XboxCompileMacros,
                            new VFetchIncludeHandler(source.FileName, false),
                            source.CompilerOptions,
                            method.Name,
                            shaderProfile,
                            Microsoft.Xna.Framework.TargetPlatform.Xbox360);
                }
                finally
                {
                    if (workingDirectory != null)
                    {
                        Directory.SetCurrentDirectory(workingDirectory);
                    }
                }
            }
            else
            {
                //this gets much trickier..
                //have to extract the args, and importantly, put them in the right place


                /*
                 *
                 * eg, a method and it's technique may look like this:
                 *
                 * float4 Test(float4 pos : POSITION, uniform float scale) : POSITION
                 * {
                 *   ... vfetch ...
                 * }
                 *
                 * technique
                 * {
                 *   VertexShader = compile vs_2_0 Test(5.0);
                 *   ...
                 * }
                 *
                 *
                 * The stub that is generated must pull the '5.0' from the technique
                 * and pass it into the real method, like so:
                 *
                 *
                 * float4 Test_STUB(float4 pos : POSITION) : POSITION
                 * {
                 *	 return Test(pos, 5.0);
                 * }
                 *
                 *
                 * Note: the uniform was removed from the stub input declaration
                 *
                 */


                //the actual arg values (passed into the real method)
                List <string> args = new List <string>();
                StringBuilder arg  = new StringBuilder();

                int depth = 0;
                //break the args list up
                for (int i = 0; i < rawArgs.Count; i++)
                {
                    if (rawArgs[i].Length == 1 && (rawArgs[i][0] == '(' || rawArgs[i][0] == '{' || rawArgs[i][0] == '['))
                    {
                        depth++;
                    }
                    if (rawArgs[i].Length == 1 && (rawArgs[i][0] == ')' || rawArgs[i][0] == '}' || rawArgs[i][0] == ']'))
                    {
                        depth--;
                    }

                    if (depth == 0 && rawArgs[i] == ",")
                    {
                        args.Add(arg.ToString());
                        arg.Length = 0;
                    }
                    else
                    {
                        arg.Append(rawArgs[i]);
                        arg.Append(' ');
                    }
                }
                args.Add(arg.ToString());


                //the input args that are being replaced must be declared as 'uniform'

                //parse the method declaration...

                depth = 0;
                HlslStructure hs          = method.HlslShader;
                bool          parsingArgs = false;
                int           argIndex    = 0;

                StringBuilder stubMethodDeclaration = new StringBuilder();
                StringBuilder stubMethodInvoke      = new StringBuilder();
                int           stubMethodInvokeCount = 0;

                //random name
                string stubName = "_STUB" + Guid.NewGuid().ToString("N");

                bool includingArg     = true;
                int  replacedArgIndex = 0;
                int  parseArgIndex    = 0;

                int  parseArgNameIndex = 0;
                bool parseCheckForName = true;

                bool stubReturnsValue = false;

                for (int i = 0; i < hs.Elements.Length; i++)
                {
                    if (hs.Elements[i].Length == 1 && (hs.Elements[i][0] == ')' || hs.Elements[i][0] == '}' || hs.Elements[i][0] == ']'))
                    {
                        depth--;
                    }
                    if (hs.Elements[i].Length == 1 && (hs.Elements[i][0] == '(' || hs.Elements[i][0] == '{' || hs.Elements[i][0] == '['))
                    {
                        depth++;

                        if (depth == 1 && hs.Elements[i][0] == '(' && !parsingArgs)
                        {
                            //about to begin the method args
                            parsingArgs = true;

                            //append the stub name, so to not conflict with the original method
                            stubMethodDeclaration.Append(stubName);
                            stubMethodDeclaration.Append('(');
                            continue;
                        }
                    }

                    //actually parsing the args within the (,,,,,) block
                    if (parsingArgs)
                    {
                        if (argIndex == 0)
                        {
                            //check for uniform.
                            if (hs.Elements[i] == "uniform" && replacedArgIndex != args.Count)
                            {
                                //replace this arg if possible


                                //add technique value to the invoke
                                if (stubMethodInvokeCount != 0)
                                {
                                    stubMethodInvoke.Append(',');
                                }

                                stubMethodInvoke.Append(args[replacedArgIndex]);
                                stubMethodInvokeCount++;

                                replacedArgIndex++;

                                //remove the last written character (a ,) from the stub method,
                                //but only if it's not the first parsed arg
                                if (parseArgIndex != 0 && includingArg)
                                {
                                    stubMethodDeclaration.Length--;
                                }

                                //skip it in the stub declaration
                                includingArg = false;
                            }
                            else
                            {
                                includingArg = true;
                            }
                        }

                        if (depth == 1 && (hs.Elements[i].Length == 1 && (hs.Elements[i][0] == ',' || hs.Elements[i][0] == ')')))
                        {
                            argIndex = 0;
                            parseArgIndex++;

                            //write the element name into the arg invoke list
                            if (includingArg)
                            {
                                if (stubMethodInvokeCount > 0)
                                {
                                    stubMethodInvoke.Append(',');
                                }

                                stubMethodInvoke.Append(hs.Elements[parseArgNameIndex]);
                                stubMethodInvokeCount++;
                            }

                            parseCheckForName = true;
                            parseArgNameIndex = 0;
                        }
                        else
                        {
                            if (includingArg)
                            {
                                //want to include the name of the arg in the invoke list.
                                if (hs.Elements[i].Length == 1 && (hs.Elements[i][0] == ':' || hs.Elements[i][0] == '='))
                                {
                                    //the arg is declared, now it's being given a default or semantic
                                    parseCheckForName = false;
                                }

                                if (parseCheckForName && depth == 1)
                                {
                                    //last value written should be the name of the arg
                                    parseArgNameIndex = i;
                                }
                            }

                            argIndex++;
                        }
                    }

                    if (includingArg || depth == 0)
                    {
                        if (stubMethodDeclaration.Length > 0 && i > 0 && Tokenizer.IsIdentifierToken(hs.Elements[i]) && Tokenizer.IsIdentifierToken(hs.Elements[i - 1]))
                        {
                            stubMethodDeclaration.Append(' ');
                        }
                        stubMethodDeclaration.Append(hs.Elements[i]);

                        if (depth == 0 && hs.Elements[i].Length == 1 && hs.Elements[i][0] == ':')
                        {
                            //method returns a value that is important somehow...
                            //ie,
                            //float4 Method() : POSITION

                            stubReturnsValue = true;
                        }
                    }
                }

                //yikes.
                //at this point,
                //stubMethodDeclaration will have the declaration of the method, without the uniform parametres
                //stubMethodInvoke will have the list of arguements to pass into the real method, from the stub method.

                //so construct the full stub


                string fullStub = string.Format("{0}{1}{5}{1}\t{2}{3}({4});{1}{6}",
                                                stubMethodDeclaration,
                                                Environment.NewLine,
                                                stubReturnsValue ? "return " : "",
                                                method.Name,
                                                stubMethodInvoke,
                                                "{", "}");

                //append it to the end of the real shader
                StringBuilder fullShader = new StringBuilder();

                fullShader.Append(source.ShaderSource);
                fullShader.AppendLine();
                fullShader.Append(fullStub);

                //now compile the bugger...

                try
                {
                    //set the working directory, since it's using CompileFromSource
                    workingDirectory = Directory.GetCurrentDirectory();

                    string path = Path.GetDirectoryName(source.FileName);
                    if (path != null && path.Length > 0)
                    {
                        Directory.SetCurrentDirectory(Path.GetDirectoryName(source.FileName));
                    }

                    //not all compiler options apply when compiling a single shader (instead of an effect)
                    CompilerOptions options = source.CompilerOptions &
                                              (CompilerOptions.AvoidFlowControl | CompilerOptions.PreferFlowControl);

                    //compile it... finally...
                    compiledShader =
                        ShaderCompiler.CompileFromSource(
                            fullShader.ToString(),
                            DecompiledEffect.XboxCompileMacros,
                            new VFetchIncludeHandler(source.FileName, false),
                            options,
                            method.Name + stubName,
                            shaderProfile,
                            Microsoft.Xna.Framework.TargetPlatform.Xbox360);
                }
                finally
                {
                    if (workingDirectory != null)
                    {
                        Directory.SetCurrentDirectory(workingDirectory);
                    }
                }
            }

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

            return(compiledShader.GetShaderCode());
        }