using System; using System.Diagnostics; using System.IO; using System.Reflection; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace MonoGame.Extended.Graphics.Effects { /// /// Reperesents the bytecode of an that is encapsulated inside a compiled assembly. /// /// /// /// Files that are encapsulated inside a compiled assembly are commonly known as Manifiest or embedded resources. /// Since embedded resources are added to the assembly at compiled time, they can not be accidentally deleted or /// misplaced. However, if the file needs to be changed, the assembly will need to be re-compiled with the changed /// file. /// /// /// To add an embedded resource file to an assembly, first add it to the project and then change the Build Action /// in the Properties of the file to Embedded Resource. The next time the project is compiled, the /// compiler will add the file to the assembly as an embedded resource. The compiler adds namespace(s) to the /// embedded resource so it matches with the path of where the file was added to the project. /// /// public class EffectResource { private static EffectResource _defaultEffect; private static string _shaderExtension; /// /// Gets the embedded into the MonoGame.Extended.Graphics library. /// public static EffectResource DefaultEffect => _defaultEffect ?? (_defaultEffect = new EffectResource($"MonoGame.Extended.Graphics.Effects.Resources.DefaultEffect.{_shaderExtension}.mgfxo")); static EffectResource() { DetermineShaderExtension(); } private static void DetermineShaderExtension() { // use reflection to figure out if Shader.Profile is OpenGL (0) or DirectX (1), // may need to be changed / fixed for future shader profiles var assembly = typeof(Game).GetTypeInfo().Assembly; Debug.Assert(assembly != null); var shaderType = assembly.GetType("Microsoft.Xna.Framework.Graphics.Shader"); Debug.Assert(shaderType != null); var shaderTypeInfo = shaderType.GetTypeInfo(); Debug.Assert(shaderTypeInfo != null); // https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/Graphics/Shader/Shader.cs#L47 var profileProperty = shaderTypeInfo.GetDeclaredProperty("Profile"); var value = (int)profileProperty.GetValue(null); switch (value) { case 0: // OpenGL _shaderExtension = "ogl"; break; case 1: // DirectX _shaderExtension = "dx11"; break; default: throw new InvalidOperationException("Unknown shader profile."); } } private readonly string _resourceName; private volatile byte[] _bytecode; private readonly Assembly _assembly; /// /// Gets the bytecode of the file. /// /// /// The bytecode of the file. /// public byte[] Bytecode { get { if (_bytecode != null) return _bytecode; lock (this) { if (_bytecode != null) return _bytecode; var stream = _assembly.GetManifestResourceStream(_resourceName); using (var memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); _bytecode = memoryStream.ToArray(); } } return _bytecode; } } /// /// Initializes a new instance of the class. /// /// The name of the embedded resource. This must include the namespace(s). /// The assembly which the embedded resource is apart of. public EffectResource(string resourceName, Assembly assembly = null) { _resourceName = resourceName; _assembly = assembly ?? typeof(EffectResource).GetTypeInfo().Assembly; } } }