diff --git a/ANX.Framework.Content.Pipeline/ANX.Framework.Content.Pipeline.csproj b/ANX.Framework.Content.Pipeline/ANX.Framework.Content.Pipeline.csproj
index ed440d92..2b030833 100644
--- a/ANX.Framework.Content.Pipeline/ANX.Framework.Content.Pipeline.csproj
+++ b/ANX.Framework.Content.Pipeline/ANX.Framework.Content.Pipeline.csproj
@@ -109,6 +109,8 @@
+
+
@@ -139,6 +141,7 @@
+
diff --git a/ANX.Framework.Content.Pipeline/AnxContentImporterContext.cs b/ANX.Framework.Content.Pipeline/AnxContentImporterContext.cs
index 9267d553..58396d21 100644
--- a/ANX.Framework.Content.Pipeline/AnxContentImporterContext.cs
+++ b/ANX.Framework.Content.Pipeline/AnxContentImporterContext.cs
@@ -21,10 +21,23 @@ namespace ANX.Framework.Content.Pipeline
public AnxContentImporterContext(BuildContent buildContent, BuildItem buildItem, ContentBuildLogger logger)
{
-
+ BuildContent = buildContent;
+ BuildItem = buildItem;
this.logger = logger;
}
+ public BuildContent BuildContent
+ {
+ get;
+ set;
+ }
+
+ public BuildItem BuildItem
+ {
+ get;
+ set;
+ }
+
public override string IntermediateDirectory
{
get
diff --git a/ANX.Framework.Content.Pipeline/AnxContentProcessorContext.cs b/ANX.Framework.Content.Pipeline/AnxContentProcessorContext.cs
index 5f57d719..e98458af 100644
--- a/ANX.Framework.Content.Pipeline/AnxContentProcessorContext.cs
+++ b/ANX.Framework.Content.Pipeline/AnxContentProcessorContext.cs
@@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using ANX.Framework.Graphics;
+using ANX.Framework.Content.Pipeline.Tasks;
+using System.IO;
#endregion
@@ -24,6 +26,23 @@ namespace ANX.Framework.Content.Pipeline
private TargetPlatform targetPlatform;
private GraphicsProfile targetProfile;
+ //public AnxContentProcessorContext(BuildCoordinator buildCoordinator, BuildItem buildItem, ContentBuildLogger logger, TargetPlatform targetPlatform, GraphicsProfile targetProfile, string buildConfiguration)
+ public AnxContentProcessorContext(BuildItem buildItem, ContentBuildLogger logger, TargetPlatform targetPlatform, GraphicsProfile targetProfile, string buildConfiguration)
+ {
+ BuildItem = buildItem;
+ this.contentBuildLogger = logger;
+ this.targetPlatform = targetPlatform;
+ this.targetProfile = targetProfile;
+ this.buildConfiguration = buildConfiguration;
+ this.intermediateDirectory = Path.GetTempPath();
+ }
+
+ public BuildItem BuildItem
+ {
+ get;
+ set;
+ }
+
public override string BuildConfiguration
{
get
@@ -50,9 +69,13 @@ namespace ANX.Framework.Content.Pipeline
public override string OutputDirectory
{
- get
- {
- return outputDirectory;
+ get
+ {
+ return outputDirectory;
+ }
+ internal set
+ {
+ outputDirectory = value;
}
}
@@ -62,6 +85,10 @@ namespace ANX.Framework.Content.Pipeline
{
return outputFilename;
}
+ internal set
+ {
+ outputFilename = value;
+ }
}
public override OpaqueDataDictionary Parameters
diff --git a/ANX.Framework.Content.Pipeline/ContentBuildLogger.cs b/ANX.Framework.Content.Pipeline/ContentBuildLogger.cs
index 9c139fbb..4ac49261 100644
--- a/ANX.Framework.Content.Pipeline/ContentBuildLogger.cs
+++ b/ANX.Framework.Content.Pipeline/ContentBuildLogger.cs
@@ -14,9 +14,10 @@ namespace ANX.Framework.Content.Pipeline
{
public abstract class ContentBuildLogger
{
+ private Stack files = new Stack();
+
protected ContentBuildLogger()
{
- throw new NotImplementedException();
}
public abstract void LogImportantMessage(string message, params Object[] messageArgs);
@@ -25,12 +26,12 @@ namespace ANX.Framework.Content.Pipeline
public void PopFile()
{
- throw new NotImplementedException();
+ files.Pop();
}
public void PushFile(string filename)
{
- throw new NotImplementedException();
+ files.Push(filename);
}
protected string GetCurrentFilename(ContentIdentity contentIdentity)
diff --git a/ANX.Framework.Content.Pipeline/ContentProcessorContext.cs b/ANX.Framework.Content.Pipeline/ContentProcessorContext.cs
index 546ba240..4be805dd 100644
--- a/ANX.Framework.Content.Pipeline/ContentProcessorContext.cs
+++ b/ANX.Framework.Content.Pipeline/ContentProcessorContext.cs
@@ -22,8 +22,8 @@ namespace ANX.Framework.Content.Pipeline
public abstract string BuildConfiguration { get; }
public abstract string IntermediateDirectory { get; }
public abstract ContentBuildLogger Logger { get; }
- public abstract string OutputDirectory { get; }
- public abstract string OutputFilename { get; }
+ public abstract string OutputDirectory { get; internal set; }
+ public abstract string OutputFilename { get; internal set; }
public abstract OpaqueDataDictionary Parameters { get; }
public abstract TargetPlatform TargetPlatform { get; }
public abstract GraphicsProfile TargetProfile { get; }
diff --git a/ANX.Framework.Content.Pipeline/Processors/EffectProcessor.cs b/ANX.Framework.Content.Pipeline/Processors/EffectProcessor.cs
index 748440d1..cc349d59 100644
--- a/ANX.Framework.Content.Pipeline/Processors/EffectProcessor.cs
+++ b/ANX.Framework.Content.Pipeline/Processors/EffectProcessor.cs
@@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using ANX.Framework.Content.Pipeline.Graphics;
+using System.IO;
+using System.ComponentModel;
#endregion
@@ -16,6 +18,9 @@ namespace ANX.Framework.Content.Pipeline.Processors
[ContentProcessor]
public class EffectProcessor : ContentProcessor
{
+ HLSLCompilerFactory hlslCompilerFactory = new HLSLCompilerFactory();
+ private string targetProfile = "fx_4_0";
+
public virtual EffectProcessorDebugMode DebugMode
{
get;
@@ -28,9 +33,24 @@ namespace ANX.Framework.Content.Pipeline.Processors
set;
}
+ [DefaultValue("fx_4_0")]
+ public virtual string TargetProfile
+ {
+ get
+ {
+ return targetProfile;
+ }
+ set
+ {
+ targetProfile = value;
+ }
+ }
+
public override CompiledEffectContent Process(EffectContent input, ContentProcessorContext context)
{
- byte[] effectCompiledCode = new byte[1]; //TODO: compile effect!!!
+ HLSLCompiler compiler = hlslCompilerFactory.Compilers.Last();
+
+ byte[] effectCompiledCode = compiler.Compile(input.EffectCode, DebugMode, TargetProfile);
return new CompiledEffectContent(effectCompiledCode)
{
@@ -39,5 +59,7 @@ namespace ANX.Framework.Content.Pipeline.Processors
OpaqueData = input.OpaqueData
};
}
+
+
}
}
diff --git a/ANX.Framework.Content.Pipeline/Processors/HLSLCompiler.cs b/ANX.Framework.Content.Pipeline/Processors/HLSLCompiler.cs
new file mode 100644
index 00000000..b4e89866
--- /dev/null
+++ b/ANX.Framework.Content.Pipeline/Processors/HLSLCompiler.cs
@@ -0,0 +1,192 @@
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Diagnostics;
+using System.IO;
+
+#endregion
+
+namespace ANX.Framework.Content.Pipeline.Processors
+{
+ public class HLSLCompiler : IComparable, IEquatable
+ {
+ private string executable;
+ private string version;
+ private string helpOutput;
+ private string[] profiles;
+
+ public HLSLCompiler(string executable)
+ {
+ if (!String.IsNullOrEmpty(executable) && File.Exists(executable))
+ {
+ this.executable = executable;
+ }
+ else
+ {
+ throw new ArgumentNullException("executable", "fxc.exe does not exist");
+ }
+ }
+
+ public string Version
+ {
+ get
+ {
+ if (String.IsNullOrEmpty(version))
+ {
+ version = CompilerVersion;
+ }
+
+ return version;
+ }
+ }
+
+ public IEnumerable SupportedProfiles
+ {
+ get
+ {
+ if (profiles == null || profiles.Length <= 0)
+ {
+ const string profileStart = @"(cs|ds|fx|ps|hs|gs|vs|tx)(_)(\S+)\s?";
+
+ Regex pattern = new Regex(profileStart, RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
+ MatchCollection m = pattern.Matches(CompilerHelpOutput);
+
+ HashSet tempProfiles = new HashSet();
+ foreach (Match profileMatch in m)
+ {
+ tempProfiles.Add(profileMatch.Value.Trim());
+ }
+
+ profiles = tempProfiles.ToArray();
+ }
+
+ return profiles;
+ }
+ }
+
+ public byte[] Compile(string source, EffectProcessorDebugMode debugMode, string targetProfile)
+ {
+ string tempInputFile = CreateTemporaryShaderFile(source);
+ string tempOutputFile = Path.GetTempFileName();
+ byte[] byteCode;
+
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = executable,
+ Arguments = String.Format("{0} {1} {2} {3}", "/Fo " + tempOutputFile, GetCompilerTargetProfile(targetProfile), GetCompilerDebugFlags(debugMode), tempInputFile),
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ CreateNoWindow = true
+ };
+
+ using (var proc = Process.Start(startInfo))
+ {
+ helpOutput = proc.StandardOutput.ReadToEnd();
+ }
+
+ byteCode = File.ReadAllBytes(tempOutputFile);
+
+ if (File.Exists(tempInputFile))
+ {
+ File.Delete(tempInputFile);
+ }
+
+ if (File.Exists(tempOutputFile))
+ {
+ File.Delete(tempOutputFile);
+ }
+
+ return byteCode;
+ }
+
+ public int CompareTo(HLSLCompiler other)
+ {
+ return Version.CompareTo(other.Version);
+ }
+
+ public bool Equals(HLSLCompiler other)
+ {
+ return String.Equals(Version, other.Version, StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ public override int GetHashCode()
+ {
+ return Version.GetHashCode();
+ }
+
+ private string GetCompilerDebugFlags(EffectProcessorDebugMode debugMode)
+ {
+ if ((debugMode == EffectProcessorDebugMode.Auto && System.Diagnostics.Debugger.IsAttached) || debugMode == EffectProcessorDebugMode.Debug)
+ {
+ return "/Od /Op /Zi";
+ }
+ else
+ {
+ return "/O3 /Qstrip_debug";
+ }
+ }
+
+ private string GetCompilerTargetProfile(string targetProfile)
+ {
+ foreach (string profile in SupportedProfiles)
+ {
+ if (string.Equals(profile, targetProfile, StringComparison.InvariantCultureIgnoreCase))
+ {
+ return String.Format("/T {0}", targetProfile);
+ }
+ }
+
+ throw new Exception(String.Format("fxc.exe version {0} does not support profile {1}", CompilerVersion, targetProfile));
+ }
+
+ private string CreateTemporaryShaderFile(string shaderSourceCode)
+ {
+ string file = Path.GetTempFileName();
+ File.WriteAllText(file, shaderSourceCode);
+ return file;
+ }
+
+ private string CompilerHelpOutput
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(helpOutput))
+ {
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = executable,
+ Arguments = @"/help",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ CreateNoWindow = true
+ };
+
+ using (var proc = Process.Start(startInfo))
+ {
+ helpOutput = proc.StandardOutput.ReadToEnd();
+ }
+ }
+
+ return helpOutput;
+ }
+ }
+
+ private string CompilerVersion
+ {
+ get
+ {
+ Regex pattern = new Regex(@"\d+(\.\d+)+");
+ Match m = pattern.Match(CompilerHelpOutput);
+ if (m.Length > 0)
+ {
+ return m.Value;
+ }
+
+ return "";
+ }
+ }
+ }
+}
diff --git a/ANX.Framework.Content.Pipeline/Processors/HLSLCompilerFactory.cs b/ANX.Framework.Content.Pipeline/Processors/HLSLCompilerFactory.cs
new file mode 100644
index 00000000..40e9cadc
--- /dev/null
+++ b/ANX.Framework.Content.Pipeline/Processors/HLSLCompilerFactory.cs
@@ -0,0 +1,80 @@
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+using System.Runtime.InteropServices;
+
+#endregion
+
+namespace ANX.Framework.Content.Pipeline.Processors
+{
+ public class HLSLCompilerFactory
+ {
+ private List compilers = new List();
+
+ public IEnumerable Compilers
+ {
+ get
+ {
+ if (compilers == null || compilers.Count <= 0)
+ {
+ HashSet tempCompilers = new HashSet();
+ HLSLCompilerExecutables.All(x => tempCompilers.Add(x)); // deduplicate list
+ compilers = new List(tempCompilers);
+ compilers.Sort();
+ }
+
+ foreach (HLSLCompiler compiler in compilers)
+ {
+ yield return compiler;
+ }
+ }
+ }
+
+ private IEnumerable ExecutablePaths
+ {
+ get
+ {
+ foreach (String subdir in new String[] { "x64", "x86" })
+ {
+ string sdkPath = Environment.GetEnvironmentVariable("DXSDK_DIR");
+ if (String.IsNullOrEmpty(sdkPath) == false)
+ {
+ yield return Path.Combine(sdkPath, subdir);
+ }
+
+ foreach (String programFilesPath in new String[] { Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
+ Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) })
+ {
+ yield return Path.Combine(Path.Combine(programFilesPath, @"Windows Kits\8.0\bin\"), subdir);
+ yield return Path.Combine(Path.Combine(programFilesPath, @"Microsoft DirectX SDK (June 2010)\Utilities\bin\"), subdir);
+ }
+ }
+ }
+ }
+
+ private IEnumerable HLSLCompilerExecutables
+ {
+ get
+ {
+ string fxcFile;
+
+ foreach (string path in ExecutablePaths)
+ {
+ fxcFile = Path.Combine(path, @"fxc.exe");
+
+ if (File.Exists(fxcFile))
+ {
+ yield return new HLSLCompiler(fxcFile);
+ }
+ }
+ }
+ }
+
+
+ }
+}
diff --git a/ANX.Framework.Content.Pipeline/Serialization/Compiler/BuiltInTypeWriter.cs b/ANX.Framework.Content.Pipeline/Serialization/Compiler/BuiltInTypeWriter.cs
index 872cedab..4584c39a 100644
--- a/ANX.Framework.Content.Pipeline/Serialization/Compiler/BuiltInTypeWriter.cs
+++ b/ANX.Framework.Content.Pipeline/Serialization/Compiler/BuiltInTypeWriter.cs
@@ -1,5 +1,6 @@
#region Using Statements
using System;
+using System.Reflection;
#endregion
@@ -13,8 +14,23 @@ namespace ANX.Framework.Content.Pipeline.Serialization.Compiler
{
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
- // TODO!
- return "";
- }
+ string @namespace = typeof(ContentTypeReader).Namespace;
+ string text = base.GetType().Name.Replace("Writer", "Reader");
+ text += base.GetGenericArgumentRuntimeTypes(targetPlatform);
+ Assembly runtimeAssembly = this.RuntimeAssembly;
+ if (runtimeAssembly != null)
+ {
+ text = text + ", " + ContentTypeWriter.GetAssemblyFullName(runtimeAssembly, targetPlatform);
+ }
+ return @namespace + '.' + text;
+ }
+
+ protected virtual Assembly RuntimeAssembly
+ {
+ get
+ {
+ return null;
+ }
+ }
}
}
diff --git a/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentCompiler.cs b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentCompiler.cs
index 7fd06b58..5e9a30d3 100644
--- a/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentCompiler.cs
+++ b/ANX.Framework.Content.Pipeline/Serialization/Compiler/ContentCompiler.cs
@@ -1,5 +1,9 @@
#region Using Statements
using System;
+using System.IO;
+using ANX.Framework.Graphics;
+using System.Collections.Generic;
+using System.Reflection;
#endregion
@@ -11,9 +15,100 @@ namespace ANX.Framework.Content.Pipeline.Serialization.Compiler
{
public sealed class ContentCompiler
{
+ private Dictionary writerInstances = new Dictionary();
+
+ public ContentCompiler()
+ {
+ foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ foreach (Type type in assembly.GetTypes())
+ {
+ ContentTypeWriterAttribute[] value = (ContentTypeWriterAttribute[])type.GetCustomAttributes(typeof(ContentTypeWriterAttribute), true);
+ if (value.Length > 0)
+ {
+ if (!type.ContainsGenericParameters)
+ {
+ ContentTypeWriter writer = (ContentTypeWriter)Activator.CreateInstance(type);
+ writerInstances[writer.TargetType] = writer;
+ }
+ else
+ {
+ //TODO: implement generic writer instances...
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+ }
+ }
+ }
+
+ internal void Compile(Stream output, object value, TargetPlatform targetPlatform, GraphicsProfile targetProfile, bool compressContent, string rootDirectory, string referenceRelocationPath)
+ {
+ if (output == null)
+ {
+ throw new ArgumentNullException("output");
+ }
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ if (!Enum.IsDefined(typeof(TargetPlatform), targetPlatform))
+ {
+ throw new ArgumentOutOfRangeException("targetPlatform");
+ }
+ if (!Enum.IsDefined(typeof(GraphicsProfile), targetProfile))
+ {
+ throw new ArgumentOutOfRangeException("targetProfile");
+ }
+ if (string.IsNullOrEmpty(rootDirectory))
+ {
+ throw new ArgumentNullException("rootDirectory");
+ }
+ if (string.IsNullOrEmpty(referenceRelocationPath))
+ {
+ throw new ArgumentNullException("referenceRelocationPath");
+ }
+ if (compressContent)
+ {
+ compressContent = this.ShouldCompressContent(targetPlatform, value);
+ }
+ using (ContentWriter contentWriter = new ContentWriter(this, output, targetPlatform, targetProfile, compressContent, rootDirectory, referenceRelocationPath))
+ {
+ contentWriter.WriteObject