diff --git a/Build/Projects/2MGFX.definition b/Build/Projects/2MGFX.definition
index d2348c38da7..aeb7753421a 100644
--- a/Build/Projects/2MGFX.definition
+++ b/Build/Projects/2MGFX.definition
@@ -160,7 +160,15 @@
MonoGame.Framework\Utilities\Hash.cs
-
+
+
+
+ MonoGame.Framework.Content.Pipeline\ExternalTool.cs
+
+
+ MonoGame.Framework.Content.Pipeline\LoadedTypeCollection.c
+
+
@@ -184,6 +192,8 @@
+
+
@@ -200,5 +210,6 @@
+
diff --git a/Build/Projects/MonoGame.Framework.Content.Pipeline.definition b/Build/Projects/MonoGame.Framework.Content.Pipeline.definition
index 07bd7682faa..db732479bb9 100644
--- a/Build/Projects/MonoGame.Framework.Content.Pipeline.definition
+++ b/Build/Projects/MonoGame.Framework.Content.Pipeline.definition
@@ -280,6 +280,14 @@
Windows
Processors\MGFX\ShaderProfile.cs
+
+ Windows
+ Processors\MGFX\ShaderProfile.OpenGL.cs
+
+
+ Windows
+ Processors\MGFX\ShaderProfile.DirectX.cs
+
Windows
Processors\MGFX\TechniqueInfo.cs
@@ -419,6 +427,7 @@
+
diff --git a/MonoGame.Framework.Content.Pipeline/ExternalTool.cs b/MonoGame.Framework.Content.Pipeline/ExternalTool.cs
index d9ba2015e6e..7ac355df334 100644
--- a/MonoGame.Framework.Content.Pipeline/ExternalTool.cs
+++ b/MonoGame.Framework.Content.Pipeline/ExternalTool.cs
@@ -139,5 +139,20 @@ private static string FindCommand(string command)
return null;
}
+
+ ///
+ /// Safely deletes the file if it exists.
+ ///
+ /// The path to the file to delete.
+ public static void DeleteFile(string filePath)
+ {
+ try
+ {
+ File.Delete(filePath);
+ }
+ catch (Exception)
+ {
+ }
+ }
}
}
diff --git a/MonoGame.Framework.Content.Pipeline/LoadedTypeCollection.cs b/MonoGame.Framework.Content.Pipeline/LoadedTypeCollection.cs
new file mode 100644
index 00000000000..ef3009a1b26
--- /dev/null
+++ b/MonoGame.Framework.Content.Pipeline/LoadedTypeCollection.cs
@@ -0,0 +1,73 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+
+namespace Microsoft.Xna.Framework.Content.Pipeline
+{
+ ///
+ /// A helper for collecting instances of a particular type
+ /// by scanning the types in loaded assemblies.
+ ///
+ public class LoadedTypeCollection : IEnumerable
+ {
+ private static List _all;
+
+ public LoadedTypeCollection()
+ {
+ // Hook into assembly loading events to gather any new
+ // enumeration types that are found.
+ AppDomain.CurrentDomain.AssemblyLoad += (sender, args) => ScanAssembly(args.LoadedAssembly);
+ }
+
+ private static void ScanAssembly(Assembly ass)
+ {
+ // Initialize the list on first use.
+ if (_all == null)
+ _all = new List(24);
+
+ var thisAss = typeof(T).Assembly;
+
+ // If the assembly doesn't reference our assembly then it
+ // cannot contain this type... so skip scanning it.
+ var refAss = ass.GetReferencedAssemblies();
+ if (thisAss.FullName != ass.FullName && refAss.All(r => r.FullName != thisAss.FullName))
+ return;
+
+ var definedTypes = ass.DefinedTypes;
+
+ foreach (var type in definedTypes)
+ {
+ if (!type.IsSubclassOf(typeof(T)) || type.IsAbstract)
+ continue;
+
+ // Create an instance of the type and add it to our list.
+ var ttype = (T)Activator.CreateInstance(type);
+ _all.Add(ttype);
+ }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ if (_all == null)
+ {
+ var assemblies = AppDomain.CurrentDomain.GetAssemblies();
+ foreach (var ass in assemblies)
+ ScanAssembly(ass);
+ }
+
+ return _all.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+}
diff --git a/MonoGame.Framework.Content.Pipeline/Processors/EffectProcessor.cs b/MonoGame.Framework.Content.Pipeline/Processors/EffectProcessor.cs
index 695c5594ead..088b934d882 100644
--- a/MonoGame.Framework.Content.Pipeline/Processors/EffectProcessor.cs
+++ b/MonoGame.Framework.Content.Pipeline/Processors/EffectProcessor.cs
@@ -54,23 +54,9 @@ public override CompiledEffectContent Process(EffectContent input, ContentProces
var options = new Options();
options.SourceFile = input.Identity.SourceFilename;
- switch (context.TargetPlatform)
- {
- case TargetPlatform.Windows:
- case TargetPlatform.WindowsPhone8:
- case TargetPlatform.WindowsStoreApp:
- options.Profile = ShaderProfile.DirectX_11;
- break;
- case TargetPlatform.iOS:
- case TargetPlatform.Android:
- case TargetPlatform.DesktopGL:
- case TargetPlatform.MacOSX:
- case TargetPlatform.RaspberryPi:
- options.Profile = ShaderProfile.OpenGL;
- break;
- default:
- throw new InvalidContentException(string.Format("{0} effects are not supported.", context.TargetPlatform), input.Identity);
- }
+ options.Profile = ShaderProfile.ForPlatform(context.TargetPlatform.ToString());
+ if (options.Profile == null)
+ throw new InvalidContentException(string.Format("{0} effects are not supported.", context.TargetPlatform), input.Identity);
options.Debug = DebugMode == EffectProcessorDebugMode.Debug;
options.Defines = Defines;
diff --git a/MonoGame.Framework.Content.Pipeline/Serialization/Compiler/ContentWriter.cs b/MonoGame.Framework.Content.Pipeline/Serialization/Compiler/ContentWriter.cs
index 678e12518a8..c69cd1d6472 100644
--- a/MonoGame.Framework.Content.Pipeline/Serialization/Compiler/ContentWriter.cs
+++ b/MonoGame.Framework.Content.Pipeline/Serialization/Compiler/ContentWriter.cs
@@ -54,6 +54,8 @@ public sealed class ContentWriter : BinaryWriter
'M', // WindowsPhone8
'r', // RaspberryPi
'P', // PlayStation4
+ 'v', // PSVita
+ 'O', // XboxOne
};
///
diff --git a/MonoGame.Framework.Content.Pipeline/TargetPlatform.cs b/MonoGame.Framework.Content.Pipeline/TargetPlatform.cs
index 60bfd09df4b..36ab710b273 100644
--- a/MonoGame.Framework.Content.Pipeline/TargetPlatform.cs
+++ b/MonoGame.Framework.Content.Pipeline/TargetPlatform.cs
@@ -90,6 +90,16 @@ public enum TargetPlatform
/// Sony PlayStation4
///
PlayStation4,
+
+ ///
+ /// PlayStation Vita
+ ///
+ PSVita,
+
+ ///
+ /// Xbox One
+ ///
+ XboxOne,
}
diff --git a/MonoGame.Framework/Content/ContentManager.cs b/MonoGame.Framework/Content/ContentManager.cs
index fe7b0d8aa41..541f88bc9d1 100644
--- a/MonoGame.Framework/Content/ContentManager.cs
+++ b/MonoGame.Framework/Content/ContentManager.cs
@@ -47,6 +47,8 @@ public partial class ContentManager : IDisposable
'M', // WindowsPhone8
'r', // RaspberryPi
'P', // PlayStation4
+ 'v', // PSVita
+ 'O', // XboxOne
// NOTE: There are additional idenfiers for consoles that
// are not defined in this repository. Be sure to ask the
diff --git a/Tools/2MGFX/CommandLineParser.cs b/Tools/2MGFX/CommandLineParser.cs
index 11d8b144817..30e82b22bfe 100644
--- a/Tools/2MGFX/CommandLineParser.cs
+++ b/Tools/2MGFX/CommandLineParser.cs
@@ -12,7 +12,7 @@
using System.ComponentModel;
-namespace Utilities
+namespace TwoMGFX
{
// Reusable, reflection based helper for parsing commandline options.
//
@@ -248,7 +248,7 @@ public sealed class RequiredAttribute : Attribute
// Used on an optionsObject field to rename the corresponding commandline option.
[AttributeUsage(AttributeTargets.Field)]
- public sealed class NameAttribute : Attribute
+ public class NameAttribute : Attribute
{
public NameAttribute(string name)
{
@@ -263,7 +263,18 @@ public NameAttribute(string name, string description)
}
public string Name { get; private set; }
- public string Description { get; private set; }
+ public string Description { get; protected set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Field)]
+ public sealed class ProfileNameAttribute : NameAttribute
+ {
+ public ProfileNameAttribute()
+ : base("Profile")
+ {
+ var names = ShaderProfile.All.Select(p => p.Name);
+ Description = "\t - Must be one of the following: " + string.Join(", ", names);
+ }
}
}
}
diff --git a/Tools/2MGFX/EffectObject.cs b/Tools/2MGFX/EffectObject.cs
index 00612e62f15..02cb2b347ea 100644
--- a/Tools/2MGFX/EffectObject.cs
+++ b/Tools/2MGFX/EffectObject.cs
@@ -683,7 +683,7 @@ static public EffectObject CompileEffect(ShaderInfo shaderInfo, out string error
pass.state_count = 0;
var tempstate = new d3dx_state[2];
- pinfo.ValidateShaderModels(shaderInfo.Profile);
+ shaderInfo.Profile.ValidateShaderModels(pinfo);
if (!string.IsNullOrEmpty(pinfo.psFunction))
{
@@ -794,44 +794,8 @@ static public EffectObject CompileEffect(ShaderInfo shaderInfo, out string error
private d3dx_state CreateShader(ShaderInfo shaderInfo, string shaderFunction, string shaderProfile, bool isVertexShader, ref string errorsAndWarnings)
{
- // Compile the shader.
- byte[] bytecode;
- if (shaderInfo.Profile == ShaderProfile.DirectX_11 || shaderInfo.Profile == ShaderProfile.OpenGL)
- {
- // For now GLSL is only supported via translation
- // using MojoShader which works from HLSL bytecode.
- bytecode = CompileHLSL(shaderInfo, shaderFunction, shaderProfile, ref errorsAndWarnings);
- }
- else if (shaderInfo.Profile == ShaderProfile.PlayStation4)
- bytecode = CompilePSSL(shaderInfo, shaderFunction, shaderProfile, ref errorsAndWarnings);
- else
- throw new NotSupportedException("Unknown shader profile!");
-
- // First look to see if we already created this same shader.
- ShaderData shaderData = null;
- foreach (var shader in Shaders)
- {
- if (bytecode.SequenceEqual(shader.Bytecode))
- {
- shaderData = shader;
- break;
- }
- }
-
- // Create a new shader.
- if (shaderData == null)
- {
- if (shaderInfo.Profile == ShaderProfile.DirectX_11)
- shaderData = ShaderData.CreateHLSL(bytecode, isVertexShader, ConstantBuffers, Shaders.Count, shaderInfo.SamplerStates, shaderInfo.Debug);
- else if (shaderInfo.Profile == ShaderProfile.OpenGL)
- shaderData = ShaderData.CreateGLSL(bytecode, isVertexShader, ConstantBuffers, Shaders.Count, shaderInfo.SamplerStates, shaderInfo.Debug);
- else if (shaderInfo.Profile == ShaderProfile.PlayStation4)
- shaderData = ShaderData.CreatePSSL(bytecode, isVertexShader, ConstantBuffers, Shaders.Count, shaderInfo.SamplerStates, shaderInfo.Debug);
- else
- throw new NotSupportedException("Unknown shader profile!");
-
- Shaders.Add(shaderData);
- }
+ // Compile and create the shader.
+ var shaderData = shaderInfo.Profile.CreateShader(shaderInfo, shaderFunction, shaderProfile, isVertexShader, this, ref errorsAndWarnings);
var state = new d3dx_state();
state.index = 0;
diff --git a/Tools/2MGFX/EffectObject.hlsl.cs b/Tools/2MGFX/EffectObject.hlsl.cs
index 0afb2a55587..8eb3fb20de1 100644
--- a/Tools/2MGFX/EffectObject.hlsl.cs
+++ b/Tools/2MGFX/EffectObject.hlsl.cs
@@ -5,7 +5,7 @@ namespace TwoMGFX
{
partial class EffectObject
{
- private static byte[] CompileHLSL(ShaderInfo shaderInfo, string shaderFunction, string shaderProfile, ref string errorsAndWarnings)
+ public static byte[] CompileHLSL(ShaderInfo shaderInfo, string shaderFunction, string shaderProfile, ref string errorsAndWarnings)
{
SharpDX.D3DCompiler.ShaderBytecode shaderByteCode;
try
diff --git a/Tools/2MGFX/EffectObject.writer.cs b/Tools/2MGFX/EffectObject.writer.cs
index 330088b0856..7463fbb3a60 100644
--- a/Tools/2MGFX/EffectObject.writer.cs
+++ b/Tools/2MGFX/EffectObject.writer.cs
@@ -25,7 +25,7 @@ public void Write(BinaryWriter writer, Options options)
// Write an simple identifier for DX11 vs GLSL
// so we can easily detect the correct shader type.
- var profile = (byte)options.Profile;
+ var profile = (byte)options.Profile.FormatId;
writer.Write(profile);
// Write the rest to a memory stream.
diff --git a/Tools/2MGFX/Options.cs b/Tools/2MGFX/Options.cs
index 60695ca3167..59507a6f3a9 100644
--- a/Tools/2MGFX/Options.cs
+++ b/Tools/2MGFX/Options.cs
@@ -1,20 +1,24 @@
-namespace TwoMGFX
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+namespace TwoMGFX
{
public class Options
{
- [Utilities.CommandLineParser.Required]
+ [CommandLineParser.Required]
public string SourceFile;
- [Utilities.CommandLineParser.Required]
+ [CommandLineParser.Required]
public string OutputFile = string.Empty;
- [Utilities.CommandLineParser.Name("Profile", "\t - Must be either DirectX_11, OpenGL, or PlayStation4")]
+ [CommandLineParser.ProfileName]
public ShaderProfile Profile = ShaderProfile.OpenGL;
- [Utilities.CommandLineParser.Name("DEBUG")]
+ [CommandLineParser.Name("Debug", "\t\t - Include extra debug information in the compiled effect.")]
public bool Debug;
- [Utilities.CommandLineParser.Name("Defines", "\t - Semicolon-delimited define assignments")]
+ [CommandLineParser.Name("Defines", "\t - Semicolon-delimited define assignments")]
public string Defines;
}
}
diff --git a/Tools/2MGFX/PassInfo.cs b/Tools/2MGFX/PassInfo.cs
index 645b2d03085..228ac2529d1 100644
--- a/Tools/2MGFX/PassInfo.cs
+++ b/Tools/2MGFX/PassInfo.cs
@@ -19,70 +19,6 @@ public class PassInfo
public RasterizerState rasterizerState;
public DepthStencilState depthStencilState;
- private static readonly Regex _hlslPixelShaderRegex = new Regex(@"^ps_(?1|2|3|4|5)_(?0|1|)(_level_(9_1|9_2|9_3))?$", RegexOptions.Compiled);
- private static readonly Regex _hlslVertexShaderRegex = new Regex(@"^vs_(?1|2|3|4|5)_(?0|1|)(_level_(9_1|9_2|9_3))?$", RegexOptions.Compiled);
-
- private static readonly Regex _glslPixelShaderRegex = new Regex(@"^ps_(?1|2|3|4|5)_(?0|1|)$", RegexOptions.Compiled);
- private static readonly Regex _glslVertexShaderRegex = new Regex(@"^vs_(?1|2|3|4|5)_(?0|1|)$", RegexOptions.Compiled);
-
-
- public static void ParseShaderModel(string text, Regex regex, out int major, out int minor)
- {
- var match = regex.Match(text);
- if (!match.Success)
- {
- major = 0;
- minor = 0;
- return;
- }
-
- major = int.Parse(match.Groups["major"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture);
- minor = int.Parse(match.Groups["minor"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture);
- }
-
- public void ValidateShaderModels(ShaderProfile profile)
- {
- int major, minor;
-
- if (!string.IsNullOrEmpty(vsFunction))
- {
- switch (profile)
- {
- case ShaderProfile.DirectX_11:
- ParseShaderModel(vsModel, _hlslVertexShaderRegex, out major, out minor);
- if (major <= 3)
- throw new Exception(String.Format("Invalid profile '{0}'. Vertex shader '{1}' must be SM 4.0 level 9.1 or higher!", vsModel, vsFunction));
- break;
- case ShaderProfile.OpenGL:
- ParseShaderModel(vsModel, _glslVertexShaderRegex, out major, out minor);
- if (major > 3)
- throw new Exception(String.Format("Invalid profile '{0}'. Vertex shader '{1}' must be SM 3.0 or lower!", vsModel, vsFunction));
- break;
- case ShaderProfile.PlayStation4:
- throw new NotSupportedException("PlayStation 4 support isn't available in this build.");
- }
- }
-
- if (!string.IsNullOrEmpty(psFunction))
- {
- switch (profile)
- {
- case ShaderProfile.DirectX_11:
- ParseShaderModel(psModel, _hlslPixelShaderRegex, out major, out minor);
- if (major <= 3)
- throw new Exception(String.Format("Invalid profile '{0}'. Pixel shader '{1}' must be SM 4.0 level 9.1 or higher!", vsModel, psFunction));
- break;
- case ShaderProfile.OpenGL:
- ParseShaderModel(psModel, _glslPixelShaderRegex, out major, out minor);
- if (major > 3)
- throw new Exception(String.Format("Invalid profile '{0}'. Pixel shader '{1}' must be SM 3.0 or lower!", vsModel, psFunction));
- break;
- case ShaderProfile.PlayStation4:
- throw new NotSupportedException("PlayStation 4 support isn't available in this build.");
- }
- }
- }
-
private static Blend ToAlphaBlend(Blend blend)
{
switch (blend)
diff --git a/Tools/2MGFX/Program.cs b/Tools/2MGFX/Program.cs
index ca7ac4cd98e..9bcfdfd9350 100644
--- a/Tools/2MGFX/Program.cs
+++ b/Tools/2MGFX/Program.cs
@@ -1,4 +1,8 @@
-using System;
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
using System.IO;
namespace TwoMGFX
@@ -14,8 +18,8 @@ public static int Main(string[] args)
}
var options = new Options();
- var parser = new Utilities.CommandLineParser(options);
- parser.Title = "2MGFX - Converts Microsoft FX files to a compiled MonoGame Effect.";
+ var parser = new CommandLineParser(options);
+ parser.Title = "2MGFX - The MonoGame Effect compiler.";
if (!parser.ParseCommandLine(args))
return 1;
diff --git a/Tools/2MGFX/ShaderData.cs b/Tools/2MGFX/ShaderData.cs
index 8a973b6eda9..ae778f4cf64 100644
--- a/Tools/2MGFX/ShaderData.cs
+++ b/Tools/2MGFX/ShaderData.cs
@@ -4,7 +4,14 @@ namespace TwoMGFX
{
internal partial class ShaderData
{
- public bool IsVertexShader;
+ public ShaderData(bool isVertexShader, int sharedIndex, byte[] bytecode)
+ {
+ IsVertexShader = isVertexShader;
+ SharedIndex = sharedIndex;
+ Bytecode = (byte[])bytecode.Clone();
+ }
+
+ public bool IsVertexShader { get; private set; }
public struct Sampler
{
@@ -35,7 +42,7 @@ public struct Attribute
public Attribute[] _attributes;
- public byte[] ShaderCode { get; private set; }
+ public byte[] ShaderCode { get; set; }
#region Non-Serialized Stuff
diff --git a/Tools/2MGFX/ShaderData.mojo.cs b/Tools/2MGFX/ShaderData.mojo.cs
index 62ee069b364..019e36a7c32 100644
--- a/Tools/2MGFX/ShaderData.mojo.cs
+++ b/Tools/2MGFX/ShaderData.mojo.cs
@@ -9,9 +9,7 @@ internal partial class ShaderData
{
public static ShaderData CreateGLSL(byte[] byteCode, bool isVertexShader, List cbuffers, int sharedIndex, Dictionary samplerStates, bool debug)
{
- var dxshader = new ShaderData ();
- dxshader.SharedIndex = sharedIndex;
- dxshader.Bytecode = (byte[])byteCode.Clone ();
+ var dxshader = new ShaderData(isVertexShader, sharedIndex, byteCode);
// Use MojoShader to convert the HLSL bytecode to GLSL.
@@ -36,18 +34,6 @@ public static ShaderData CreateGLSL(byte[] byteCode, bool isVertexShader, List cbuffers, int sharedIndex, Dictionary samplerStates, bool debug)
{
- var dxshader = new ShaderData();
- dxshader.IsVertexShader = isVertexShader;
- dxshader.SharedIndex = sharedIndex;
- dxshader.Bytecode = (byte[])byteCode.Clone();
+ var dxshader = new ShaderData(isVertexShader, sharedIndex, byteCode);
dxshader._attributes = new Attribute[0];
// Strip the bytecode we're gonna save!
diff --git a/Tools/2MGFX/ShaderInfo.cs b/Tools/2MGFX/ShaderInfo.cs
index b71d6535402..19236e7d48e 100644
--- a/Tools/2MGFX/ShaderInfo.cs
+++ b/Tools/2MGFX/ShaderInfo.cs
@@ -1,4 +1,8 @@
-using System;
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
using System.Collections.Generic;
using System.IO;
@@ -17,6 +21,7 @@ public class ShaderInfo
public bool Debug { get; private set; }
public List Techniques = new List();
+
public Dictionary SamplerStates = new Dictionary();
public List Dependencies { get; private set; }
@@ -34,21 +39,7 @@ static public ShaderInfo FromString(string effectSource, string filePath, Option
var macros = new Dictionary();
macros.Add("MGFX", "1");
- // Under the DX11 profile we pass a few more macros.
- if (options.Profile == ShaderProfile.DirectX_11)
- {
- macros.Add("HLSL", "1");
- macros.Add("SM4", "1");
- }
- else if (options.Profile == ShaderProfile.OpenGL)
- {
- macros.Add("GLSL", "1");
- macros.Add("OPENGL", "1");
- }
- else if (options.Profile == ShaderProfile.PlayStation4)
- {
- throw new NotSupportedException("PlayStation 4 support isn't available in this build.");
- }
+ options.Profile.AddMacros(macros);
// If we're building shaders for debug set that flag too.
if (options.Debug)
diff --git a/Tools/2MGFX/ShaderProfile.DirectX.cs b/Tools/2MGFX/ShaderProfile.DirectX.cs
new file mode 100644
index 00000000000..978801a503a
--- /dev/null
+++ b/Tools/2MGFX/ShaderProfile.DirectX.cs
@@ -0,0 +1,73 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace TwoMGFX
+{
+ class DirectX11ShaderProfile : ShaderProfile
+ {
+ private static readonly Regex HlslPixelShaderRegex = new Regex(@"^ps_(?1|2|3|4|5)_(?0|1|)(_level_(9_1|9_2|9_3))?$", RegexOptions.Compiled);
+ private static readonly Regex HlslVertexShaderRegex = new Regex(@"^vs_(?1|2|3|4|5)_(?0|1|)(_level_(9_1|9_2|9_3))?$", RegexOptions.Compiled);
+
+ public DirectX11ShaderProfile()
+ : base("DirectX_11", 1)
+ {
+ }
+
+ internal override void AddMacros(Dictionary macros)
+ {
+ macros.Add("HLSL", "1");
+ macros.Add("SM4", "1");
+ }
+
+ internal override void ValidateShaderModels(PassInfo pass)
+ {
+ int major, minor;
+
+ if (!string.IsNullOrEmpty(pass.vsFunction))
+ {
+ ParseShaderModel(pass.vsModel, HlslVertexShaderRegex, out major, out minor);
+ if (major <= 3)
+ throw new Exception(String.Format("Invalid profile '{0}'. Vertex shader '{1}' must be SM 4.0 level 9.1 or higher!", pass.vsModel, pass.vsFunction));
+ }
+
+ if (!string.IsNullOrEmpty(pass.psFunction))
+ {
+ ParseShaderModel(pass.psModel, HlslPixelShaderRegex, out major, out minor);
+ if (major <= 3)
+ throw new Exception(String.Format("Invalid profile '{0}'. Pixel shader '{1}' must be SM 4.0 level 9.1 or higher!", pass.vsModel, pass.psFunction));
+ }
+ }
+
+ internal override ShaderData CreateShader(ShaderInfo shaderInfo, string shaderFunction, string shaderProfile, bool isVertexShader, EffectObject effect, ref string errorsAndWarnings)
+ {
+ var bytecode = EffectObject.CompileHLSL(shaderInfo, shaderFunction, shaderProfile, ref errorsAndWarnings);
+
+ // First look to see if we already created this same shader.
+ foreach (var shader in effect.Shaders)
+ {
+ if (bytecode.SequenceEqual(shader.Bytecode))
+ return shader;
+ }
+
+ var shaderData = ShaderData.CreateHLSL(bytecode, isVertexShader, effect.ConstantBuffers, effect.Shaders.Count, shaderInfo.SamplerStates, shaderInfo.Debug);
+ effect.Shaders.Add(shaderData);
+ return shaderData;
+ }
+
+ internal override bool Supports(string platform)
+ {
+ if (platform == "Windows" ||
+ platform == "WindowsPhone8" ||
+ platform == "WindowsStoreApp")
+ return true;
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Tools/2MGFX/ShaderProfile.OpenGL.cs b/Tools/2MGFX/ShaderProfile.OpenGL.cs
new file mode 100644
index 00000000000..a3c723e825a
--- /dev/null
+++ b/Tools/2MGFX/ShaderProfile.OpenGL.cs
@@ -0,0 +1,78 @@
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace TwoMGFX
+{
+ class OpenGLShaderProfile : ShaderProfile
+ {
+ private static readonly Regex GlslPixelShaderRegex = new Regex(@"^ps_(?1|2|3|4|5)_(?0|1|)$", RegexOptions.Compiled);
+ private static readonly Regex GlslVertexShaderRegex = new Regex(@"^vs_(?1|2|3|4|5)_(?0|1|)$", RegexOptions.Compiled);
+
+ public OpenGLShaderProfile()
+ : base("OpenGL", 0)
+ {
+ }
+
+ internal override void AddMacros(Dictionary macros)
+ {
+ macros.Add("GLSL", "1");
+ macros.Add("OPENGL", "1");
+ }
+
+ internal override void ValidateShaderModels(PassInfo pass)
+ {
+ int major, minor;
+
+ if (!string.IsNullOrEmpty(pass.vsFunction))
+ {
+ ParseShaderModel(pass.vsModel, GlslVertexShaderRegex, out major, out minor);
+ if (major > 3)
+ throw new Exception(String.Format("Invalid profile '{0}'. Vertex shader '{1}' must be SM 3.0 or lower!", pass.vsModel, pass.vsFunction));
+ }
+
+ if (!string.IsNullOrEmpty(pass.psFunction))
+ {
+ ParseShaderModel(pass.psModel, GlslPixelShaderRegex, out major, out minor);
+ if (major > 3)
+ throw new Exception(String.Format("Invalid profile '{0}'. Pixel shader '{1}' must be SM 3.0 or lower!", pass.vsModel, pass.psFunction));
+ }
+ }
+
+ internal override ShaderData CreateShader(ShaderInfo shaderInfo, string shaderFunction, string shaderProfile, bool isVertexShader, EffectObject effect, ref string errorsAndWarnings)
+ {
+ // For now GLSL is only supported via translation
+ // using MojoShader which works from HLSL bytecode.
+ var bytecode = EffectObject.CompileHLSL(shaderInfo, shaderFunction, shaderProfile, ref errorsAndWarnings);
+
+ // First look to see if we already created this same shader.
+ foreach (var shader in effect.Shaders)
+ {
+ if (bytecode.SequenceEqual(shader.Bytecode))
+ return shader;
+ }
+
+ var shaderData = ShaderData.CreateGLSL(bytecode, isVertexShader, effect.ConstantBuffers, effect.Shaders.Count, shaderInfo.SamplerStates, shaderInfo.Debug);
+ effect.Shaders.Add(shaderData);
+
+ return shaderData;
+ }
+
+ internal override bool Supports(string platform)
+ {
+ if (platform == "iOS" ||
+ platform == "Android" ||
+ platform == "DesktopGL" ||
+ platform == "MacOSX" ||
+ platform == "RaspberryPi")
+ return true;
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Tools/2MGFX/ShaderProfile.cs b/Tools/2MGFX/ShaderProfile.cs
index fbd9270f091..8c7bb595a21 100644
--- a/Tools/2MGFX/ShaderProfile.cs
+++ b/Tools/2MGFX/ShaderProfile.cs
@@ -1,11 +1,106 @@
-namespace TwoMGFX
+// MonoGame - Copyright (C) The MonoGame Team
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE.txt', which is part of this source code package.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace TwoMGFX
{
- public enum ShaderProfile
+ [TypeConverter(typeof(StringConverter))]
+ public abstract class ShaderProfile
{
- // NOTE: This order matters and is used as part
- // of the file format... don't change it.
- OpenGL = 0,
- DirectX_11 = 1,
- PlayStation4 = 2,
+ private static readonly LoadedTypeCollection _profiles = new LoadedTypeCollection();
+
+ protected ShaderProfile(string name, byte formatId)
+ {
+ Name = name;
+ FormatId = formatId;
+ }
+
+ public static readonly ShaderProfile OpenGL = FromName("OpenGL");
+
+ public static readonly ShaderProfile DirectX_11 = FromName("DirectX_11");
+
+ ///
+ /// Returns all the loaded shader profiles.
+ ///
+ public static IEnumerable All
+ {
+ get { return _profiles; }
+ }
+
+ ///
+ /// Returns the name of the shader profile.
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Returns the format identifier used in the MGFX file format.
+ ///
+ public byte FormatId { get; private set; }
+
+ ///
+ /// Returns the correct profile for the named platform or
+ /// null if no supporting profile is found.
+ ///
+ public static ShaderProfile ForPlatform(string platform)
+ {
+ return _profiles.FirstOrDefault(p => p.Supports(platform));
+ }
+
+ ///
+ /// Returns the profile by name or null if no match is found.
+ ///
+ public static ShaderProfile FromName(string name)
+ {
+ return _profiles.FirstOrDefault(p => p.Name == name);
+ }
+
+ internal abstract void AddMacros(Dictionary macros);
+
+ internal abstract void ValidateShaderModels(PassInfo pass);
+
+ internal abstract ShaderData CreateShader(ShaderInfo shaderInfo, string shaderFunction, string shaderProfile, bool isVertexShader, EffectObject effect, ref string errorsAndWarnings);
+
+ internal abstract bool Supports(string platform);
+
+ protected static void ParseShaderModel(string text, Regex regex, out int major, out int minor)
+ {
+ var match = regex.Match(text);
+ if (!match.Success)
+ {
+ major = 0;
+ minor = 0;
+ return;
+ }
+
+ major = int.Parse(match.Groups["major"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture);
+ minor = int.Parse(match.Groups["minor"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture);
+ }
+
+ private class StringConverter : TypeConverter
+ {
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ if (value is string)
+ {
+ var name = value as string;
+
+ foreach (var e in All)
+ {
+ if (e.Name == name)
+ return e;
+ }
+ }
+
+ return base.ConvertFrom(context, culture, value);
+ }
+ }
}
}
\ No newline at end of file