using System; using System.Collections.Generic; using System.Reflection; using HTraceWSGI.Scripts.Structs; using UnityEditor; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; namespace HTraceWSGI.Scripts.Globals { public static class HExtensions { public static string ERROR_OUT_RANGE_VALUE = "Your \"{0}\" value is out of range: {1}"; public static ComputeShader LoadComputeShader(string shaderName) { var computeShader = (ComputeShader)Resources.Load($"HTRaceWSGI/Computes/{shaderName}"); if (computeShader == null) { Debug.LogError($"{shaderName} is missing in HTraceWSGI/Resources/Computes folder"); return null; } return computeShader; } public static HDRenderPipelineAsset CurrentAsset { get { return GraphicsSettings.currentRenderPipeline is HDRenderPipelineAsset hdrpAsset ? hdrpAsset : null; } } private static HDRenderPipelineAsset _hdrpAsset; public static HDRenderPipelineAsset HdrpAsset { get { if (_hdrpAsset == null) { if (GraphicsSettings.currentRenderPipeline is HDRenderPipelineAsset hdrpAsset) _hdrpAsset = hdrpAsset; } return _hdrpAsset; } } internal static bool PipelineSupportsScreenSpaceShadows => HdrpAsset != null ? HdrpAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams.supportScreenSpaceShadows : false; internal static bool PipelineSupportsSSGI => HdrpAsset != null ? HdrpAsset.currentPlatformRenderPipelineSettings.supportSSGI : false; public static T GetCopyOf(this Component comp, T other) where T : Component { Type type = comp.GetType(); if (type != other.GetType()) return null; // type mis-match BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default | BindingFlags.DeclaredOnly; PropertyInfo[] pinfos = type.GetProperties(flags); foreach (var pinfo in pinfos) { if (pinfo.CanWrite) { try { pinfo.SetValue(comp, pinfo.GetValue(other, null), null); } catch { } // In case of NotImplementedException being thrown. For some reason specifying that exception didn't seem to catch it, so I didn't catch anything specific. } } FieldInfo[] finfos = type.GetFields(flags); foreach (var finfo in finfos) { finfo.SetValue(comp, finfo.GetValue(other)); } return comp as T; } public static T AddComponent(this GameObject go, T toAdd) where T : Component { return go.AddComponent().GetCopyOf(toAdd) as T; } public static void RemoveComponent(Component component, bool immediate = false) { if (component != null) { if (immediate) { UnityEngine.Object.DestroyImmediate(component as UnityEngine.Object, true); } else { UnityEngine.Object.Destroy(component as UnityEngine.Object); } } } public static T Next(this T src) where T : struct { if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argument {0} is not an Enum", typeof(T).FullName)); T[] Arr = (T[])Enum.GetValues(src.GetType()); int j = Array.IndexOf(Arr, src) + 1; return (Arr.Length == j) ? Arr[0] : Arr[j]; } public static void HRelease(RTHandle rtHandle) { RTHandles.Release(rtHandle); } public static void HRelease(ComputeBuffer cumputeBuffer) { if (cumputeBuffer != null) cumputeBuffer.Release(); } public static int ParseToProbeSize(this RayCountMode rayCountMode) { switch (rayCountMode) { case RayCountMode.Performance: return 8; case RayCountMode.Quality: return 6; case RayCountMode.Cinematic: return 4; } return 6; } //custom Attributes #if UNITY_EDITOR /// /// Read Only attribute. /// Attribute is use only to mark ReadOnly properties. /// public class ReadOnlyAttribute : PropertyAttribute { } /// /// This class contain custom drawer for ReadOnly attribute. /// [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] public class ReadOnlyDrawer : PropertyDrawer { /// /// Unity method for drawing GUI in Editor /// /// Position. /// Property. /// Label. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // Saving previous GUI enabled value var previousGUIState = GUI.enabled; // Disabling edit for property GUI.enabled = false; // Drawing Property EditorGUI.PropertyField(position, property, label); // Setting old GUI enabled value GUI.enabled = previousGUIState; } } #endif /// /// Attribute used to make a float or int variable in a script be restricted to a specific range. /// [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class HRangeAttribute : Attribute { public readonly bool isFloat; public readonly float minFloat; public readonly float maxFloat; public readonly int minInt; public readonly int maxInt; /// /// Attribute used to make a float or int variable in a script be restricted to a specific range. /// /// The minimum allowed value. /// The maximum allowed value. public HRangeAttribute(float minFloat, float maxFloat) { this.minFloat = minFloat; this.maxFloat = maxFloat; isFloat = true; } /// /// Attribute used to make a float or int variable in a script be restricted to a specific range. /// /// The minimum allowed value. /// The maximum allowed value. public HRangeAttribute(int minInt, int maxInt) { this.minInt = minInt; this.maxInt = maxInt; isFloat = false; } } public struct HRangeAttributeElement { public bool isFloat; public float minFloat; public float maxFloat; public int minInt; public int maxInt; } public static readonly Dictionary HRangeAttributeDictionary = new Dictionary(); public static void FillAttributeDictionary() { if (HRangeAttributeDictionary.Count != 0) return; List props = new List(); props.AddRange(typeof(GeneralData).GetProperties()); props.AddRange(typeof(ScreenSpaceLightingData).GetProperties()); props.AddRange(typeof(VoxelizationData).GetProperties()); foreach (PropertyInfo prop in props) { object[] attrs = prop.GetCustomAttributes(true); foreach (object attr in attrs) { HRangeAttribute authAttr = attr as HRangeAttribute; if (authAttr != null) { string propName = prop.Name; HRangeAttributeElement auth = new HRangeAttributeElement() { isFloat = authAttr.isFloat, minFloat = authAttr.minFloat, maxFloat = authAttr.maxFloat, minInt = authAttr.minInt, maxInt = authAttr.maxInt, }; HRangeAttributeDictionary.Add(propName, auth); } } } } } }