using System; using UnityEngine; namespace Yum.Fold { [Serializable] public sealed class FoldOperator { // Packed shader/animation storage. Named fields, defaults and jumpback // policies live in the per-operator definitions in FoldOperators.cs. public bool enabled; public int opcode; public float float0, float1, float2, float3; public Vector4 vector0, vector1, vector2, vector3; public static FoldOperator Defaults(int opcode) => FoldOperators.Defaults(opcode); public FoldOperator JumpbackDefaults() => FoldOperators.Jumpback(this); public static FoldOperator AnimationDefaults(int opcode) => Defaults(opcode).JumpbackDefaults(); public FoldOperator Copy() => (FoldOperator)MemberwiseClone(); public static string Prefix(int slot) => "_Vertex_Deformation_Slot_" + slot + "_"; public static FoldOperator Read(Material material, int slot) { string p = Prefix(slot); return new FoldOperator { enabled = material.GetFloat(p + "Enabled") > .5f, opcode = material.GetInteger(p + "Opcode"), float0 = material.GetFloat(p + "Float_0"), float1 = material.GetFloat(p + "Float_1"), float2 = material.GetFloat(p + "Float_2"), float3 = material.GetFloat(p + "Float_3"), vector0 = material.GetVector(p + "Vector_0"), vector1 = material.GetVector(p + "Vector_1"), vector2 = material.GetVector(p + "Vector_2"), vector3 = material.GetVector(p + "Vector_3") }; } public void Write(Material material, int slot) { string p = Prefix(slot); material.SetFloat(p + "Enabled", enabled ? 1 : 0); material.SetInteger(p + "Opcode", opcode); material.SetFloat(p + "Float_0", float0); material.SetFloat(p + "Float_1", float1); material.SetFloat(p + "Float_2", float2); material.SetFloat(p + "Float_3", float3); material.SetVector(p + "Vector_0", vector0); material.SetVector(p + "Vector_1", vector1); material.SetVector(p + "Vector_2", vector2); material.SetVector(p + "Vector_3", vector3); } static readonly int[][] PropertyIds = CreatePropertyIds(); static int[][] CreatePropertyIds() { var ids = new int[16][]; string[] names = { "Enabled", "Opcode", "Float_0", "Float_1", "Float_2", "Float_3", "Vector_0", "Vector_1", "Vector_2", "Vector_3" }; for (int i = 0; i < 16; i++) { ids[i] = new int[names.Length]; for (int j = 0; j < names.Length; j++) ids[i][j] = Shader.PropertyToID(Prefix(i) + names[j]); } return ids; } public void Write(MaterialPropertyBlock block, int slot) { var ids = PropertyIds[slot]; block.SetFloat(ids[0], enabled ? 1 : 0); block.SetInteger(ids[1], opcode); block.SetFloat(ids[2], float0); block.SetFloat(ids[3], float1); block.SetFloat(ids[4], float2); block.SetFloat(ids[5], float3); block.SetVector(ids[6], vector0); block.SetVector(ids[7], vector1); block.SetVector(ids[8], vector2); block.SetVector(ids[9], vector3); } } [ExecuteAlways, DisallowMultipleComponent, RequireComponent(typeof(Renderer))] [AddComponentMenu("Yum Food/Fold Stack")] public sealed class FoldStack : MonoBehaviour { public FoldMaterialAnimator[] materials = Array.Empty(); public static bool Compatible(Material material) { if (!material || !material.shader || material.shader.name != "yum_food/3ner") return false; if (material.HasProperty("_ShaderOptimizerEnabled") && material.GetFloat("_ShaderOptimizerEnabled") != 0) return false; if (!material.HasProperty("_Vertex_Deformation_Enabled")) return false; for (int i = 0; i < 16; i++) { string p = FoldOperator.Prefix(i); if (!material.HasProperty(p + "Enabled") || !material.HasProperty(p + "Opcode")) return false; for (int j = 0; j < 4; j++) if (!material.HasProperty(p + "Float_" + j) || !material.HasProperty(p + "Vector_" + j)) return false; } return true; } public void Apply() { foreach (var material in materials) if (material) material.Apply(); } void OnEnable() => Apply(); void OnDisable() { foreach (var material in materials) if (material) material.Restore(); } } }