using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace PoroCYon.FNAGLSL { public static class ReflUtil { readonly static FieldInfo gd_GLDevice_fi = typeof(GraphicsDevice).GetField( "GLDevice", BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance); readonly static FieldInfo ef_glEffect_fi = typeof(Effect).GetField( "glEffect", BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance); readonly static FieldInfo ep_texture_fi = typeof(EffectParameter).GetField( "texture" , BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance); readonly static FieldInfo tx_texture_fi = typeof(Texture).GetField( "texture" , BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance); readonly static PropertyInfo ef_Techniques_pi = typeof(Effect).GetProperty( "Techniques", BindingFlags.SetProperty|BindingFlags.Public|BindingFlags.Instance), ef_Parameters_pi = typeof(Effect).GetProperty( "Parameters", BindingFlags.SetProperty|BindingFlags.Public|BindingFlags.Instance); readonly static ConstructorInfo ci_EffTechColl, ci_EffParamColl, ci_EffAnnotColl, ci_EffTech, ci_EffParam, ci_EffAnnot; readonly static int ci_EffParam_plen; static MethodInfo gldev_DeleteEffect_mi; static PropertyInfo ef_GLEffectData_pi, ef_EffectData_pi, gltex_Handle_pi, gltex_Target_pi; static ReflUtil() { var pm1f = new ParameterModifier(1); pm1f[0] = false; var pm4f = new ParameterModifier(4); pm4f[3] = pm4f[2] = pm4f[1] = pm4f[0] = false; var pm11f = new ParameterModifier(11); pm11f[3] = pm11f[2] = pm11f[1] = pm11f[0] = false; pm11f[7] = pm11f[6] = pm11f[5] = pm11f[4] = false; pm11f[10]= pm11f[9] = pm11f[8] = false; var pm7f = new ParameterModifier(7); pm7f[3] = pm7f[2] = pm7f[1] = pm7f[0] = false; pm7f[6] = pm7f[5] = pm7f[4] = false; var pm1fa = new[]{pm1f}; ci_EffTechColl = typeof(EffectTechniqueCollection) .GetConstructor(BindingFlags.CreateInstance|BindingFlags.NonPublic|BindingFlags.Instance, null, new[]{typeof(List)}, pm1fa); ci_EffParamColl = typeof(EffectParameterCollection) .GetConstructor(BindingFlags.CreateInstance|BindingFlags.NonPublic|BindingFlags.Instance, null, new[]{typeof(List)}, pm1fa); ci_EffAnnotColl = typeof(EffectAnnotationCollection) .GetConstructor(BindingFlags.CreateInstance|BindingFlags.NonPublic|BindingFlags.Instance, null, new[]{typeof(List)}, pm1fa); ci_EffTech = typeof(EffectTechnique).GetConstructor( BindingFlags.CreateInstance|BindingFlags.NonPublic|BindingFlags.Instance, null, new[]{typeof(string), typeof(IntPtr), typeof(EffectPassCollection), typeof(EffectAnnotationCollection)}, new[]{pm4f}); ci_EffParam = /*typeof(EffectParameter).GetConstructor( // FIXME: no worky BindingFlags.CreateInstance|BindingFlags.NonPublic|BindingFlags.Instance, null, new[]{typeof(string), typeof(string), typeof(int), typeof(int), typeof(int), typeof(EffectParameterClass), typeof(EffectParameterType), typeof(EffectParameterCollection), typeof(EffectAnnotationCollection), typeof(IntPtr), typeof(uint)}, new[]{pm11f});*/ // fuck it typeof(EffectParameter).GetConstructors(BindingFlags.Instance |BindingFlags.CreateInstance|BindingFlags.NonPublic)[0]; // ^ turns out, depending on the FNA version, the dataSize (uint) // parameter mightn't be included ci_EffParam_plen = ci_EffParam.GetParameters().Length; ci_EffAnnot = typeof(EffectAnnotation).GetConstructor( BindingFlags.CreateInstance|BindingFlags.NonPublic|BindingFlags.Instance, null, new[]{typeof(string), typeof(string), typeof(int), typeof(int), typeof(EffectParameterClass), typeof(EffectParameterType), typeof(IntPtr)}, new[]{pm7f}); if (ci_EffTechColl == null || ci_EffParamColl == null || ci_EffAnnotColl == null || ci_EffTech == null || ci_EffParam == null || ci_EffAnnot == null) throw new Exception("can't find ctors"); } public static object GLDevice(this GraphicsDevice gd) => gd_GLDevice_fi.GetValue(gd); public static object glEffect(this Effect eff) => ef_glEffect_fi.GetValue(eff); static object[] arg1 = new object[1]; public static void DeleteEffect(this GraphicsDevice gd, Effect eff) { var gldev = gd.GLDevice(); if (gldev_DeleteEffect_mi == null) { // type of the gldev not known at compile-time! gldev_DeleteEffect_mi = gldev.GetType().GetMethod("DeleteEffect", BindingFlags.InvokeMethod|BindingFlags.NonPublic|BindingFlags.Instance); } arg1[0] = eff.glEffect(); gldev_DeleteEffect_mi.Invoke(gldev, arg1); } public static IntPtr GetGLEffectData(this Effect eff) { var gleff = eff.glEffect(); if (ef_GLEffectData_pi == null) { // type of the gleff not known at compile-time! ef_GLEffectData_pi = gleff.GetType().GetProperty("GLEffectData", BindingFlags.SetProperty|BindingFlags.NonPublic|BindingFlags.Instance); } return (IntPtr)ef_GLEffectData_pi.GetValue(gleff, null); } public static void SetGLEffectData(this Effect eff, IntPtr value) { var gleff = eff.glEffect(); if (ef_GLEffectData_pi == null) { // type of the gleff not known at compile-time! ef_GLEffectData_pi = gleff.GetType().GetProperty("GLEffectData", BindingFlags.SetProperty|BindingFlags.NonPublic|BindingFlags.Instance); } ef_GLEffectData_pi.SetValue(gleff, value, null); } public static IntPtr GetEffectData(this Effect eff) { var gleff = eff.glEffect(); if (ef_EffectData_pi == null) { // type of the gleff not known at compile-time! ef_EffectData_pi = gleff.GetType().GetProperty("EffectData", BindingFlags.SetProperty|BindingFlags.NonPublic|BindingFlags.Instance); } return (IntPtr)ef_EffectData_pi.GetValue(gleff, null); } public static void SetEffectData(this Effect eff, IntPtr value) { var gleff = eff.glEffect(); if (ef_EffectData_pi == null) { // type of the gleff not known at compile-time! ef_EffectData_pi = gleff.GetType().GetProperty("EffectData", BindingFlags.SetProperty|BindingFlags.NonPublic|BindingFlags.Instance); } ef_EffectData_pi.SetValue(gleff, value, null); } public static void SetTechniques(this Effect eff, EffectTechniqueCollection value) { ef_Techniques_pi.SetValue(eff, value, null); } public static void SetParameters(this Effect eff, EffectParameterCollection value) { ef_Parameters_pi.SetValue(eff, value, null); } public static EffectTechniqueCollection CreateTechColl(List techniques) => (EffectTechniqueCollection)ci_EffTechColl.Invoke(new[]{techniques}); public static EffectParameterCollection CreateParamColl(List parms) => (EffectParameterCollection)ci_EffParamColl.Invoke(new[]{parms}); public static EffectAnnotationCollection CreateAnnotColl(List annots) => (EffectAnnotationCollection)ci_EffAnnotColl.Invoke(new[]{annots}); public static EffectTechnique CreateTechnique(string name, IntPtr pointer, EffectPassCollection passes, EffectAnnotationCollection annots) => (EffectTechnique)ci_EffTech.Invoke(new object[]{name, pointer, passes, annots}); public static EffectParameter CreateParameter(string name, string semantic, int rowCount, int colCount, int elemCount, EffectParameterClass paramClass, EffectParameterType paramType, EffectParameterCollection structMembers, EffectAnnotationCollection annots, IntPtr data, uint dataSize) { int plen = ci_EffParam_plen; if (plen == 11) { return (EffectParameter)ci_EffParam.Invoke(new object[]{name, semantic, rowCount, colCount, elemCount, paramClass, paramType, structMembers, annots, data, dataSize}); } else if (plen == 10) { return (EffectParameter)ci_EffParam.Invoke(new object[]{name, semantic, rowCount, colCount, elemCount, paramClass, paramType, structMembers, annots, data}); } else { throw new NotSupportedException("Unsupported nargs for EffectParameter ctor! (" + plen + ")"); } } public static EffectAnnotation CreateAnnotation(string name, string semantic, int rowCount, int colCount, EffectParameterClass paramClass, EffectParameterType paramType, IntPtr data) => (EffectAnnotation)ci_EffAnnot.Invoke(new object[]{name, semantic, rowCount, colCount, paramClass, paramType, data}); public static Texture GetValueTexture(this EffectParameter ep) => (Texture)ep_texture_fi.GetValue(ep); public static uint GetGLTexID(this Texture tex) { // gl object id var igltex = tx_texture_fi.GetValue(tex); if (gltex_Handle_pi == null) { // IGLTexture type not known at compile-time gltex_Handle_pi = igltex.GetType().GetProperty("Handle", BindingFlags.GetProperty|BindingFlags.Instance|BindingFlags.Public); } return (uint)gltex_Handle_pi.GetValue(igltex, null); } public static int GetGLTexTarget(this Texture tex) { // GL_TEXTURE_[123]D etc var igltex = tx_texture_fi.GetValue(tex); if (gltex_Target_pi == null) { // IGLTexture type not known at compile-time gltex_Target_pi = igltex.GetType().GetProperty("Target", BindingFlags.GetProperty|BindingFlags.Instance|BindingFlags.Public); } return (int)gltex_Target_pi.GetValue(igltex, null); } } }