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;
}
}
}