using UnityEngine; using UnityEngine.Events; using System.Collections.Generic; using CW.Common; namespace PaintIn3D { /// This component can generate a mask texture from the specified mesh. This can be used with the P3dPaintableTexture component's Advanced / LocalMask setting. //[ExecuteInEditMode] [HelpURL(P3dCommon.HelpUrlPrefix + "P3dGenerateMask")] [AddComponentMenu(P3dCommon.ComponentMenuPrefix + "Generate Mask")] public class P3dGenerateMask : MonoBehaviour { public enum ApplyType { Manually, Siblings, SiblingsAndDescendants } [System.Serializable] public class RenderTextureEvent : UnityEvent {} /// The mask will be generated from this mesh. public Mesh Mesh { set { mesh = value; } get { return mesh; } } [SerializeField] private Mesh mesh; /// The mask will be generated from this submesh of the mesh. public int Submesh { set { submesh = value; } get { return submesh; } } [SerializeField] private int submesh; /// The texture channel of the mesh the mask will be generated from. public P3dCoord Coord { set { coord = value; } get { return coord; } } [SerializeField] private P3dCoord coord; /// The size of the generated texture. public Vector2Int Size { set { size = value; } get { return size; } } [SerializeField] private Vector2Int size = new Vector2Int(512, 512); /// The format of the generated texture. public RenderTextureFormat Format { set { format = value; } get { return format; } } [SerializeField] private RenderTextureFormat format = RenderTextureFormat.R8; /// Should the generated mask be automatically applied? /// Manually = Use the OnGenerated event to apply the mask to specific components. /// Siblings = The mask will be applied to all P3dPaintableTexture components on this GameObject. /// SiblingsAndDescendants = Like Siblings, but also all child GameObjects. public ApplyType ApplyTo { set { applyTo = value; } get { return applyTo; } } [SerializeField] private ApplyType applyTo = ApplyType.Siblings; /// After the mask is generated, this event will be invoked. public RenderTextureEvent OnGenerated { get { if (onGenerated == null) onGenerated = new RenderTextureEvent(); return onGenerated; } } [SerializeField] private RenderTextureEvent onGenerated; [System.NonSerialized] private RenderTexture generatedTexture; private static List tempPaintableTextures = new List(); /// This allows you to access the generated texture. public RenderTexture GeneratedTexture { get { return generatedTexture; } } /// This method will destroy the generated texture. [ContextMenu("Clear")] public void Clear() { DestroyImmediate(generatedTexture); generatedTexture = null; } /// This method will generate a mask texture based on the specified settings. [ContextMenu("Generate")] public RenderTexture Generate() { TryGenerate(); return generatedTexture; } public bool TryGenerate() { Clear(); if (size.x > 0 && size.y > 0) { generatedTexture = new RenderTexture(size.x, size.y, 0, format); generatedTexture.name = "Generated Mask"; P3dCommandReplace.Blit(generatedTexture, default(Texture), Color.black); P3dBlit.White(generatedTexture, mesh, submesh, coord); if (applyTo != ApplyType.Manually) { if (applyTo == ApplyType.SiblingsAndDescendants) { GetComponentsInChildren(tempPaintableTextures); } else { GetComponents(tempPaintableTextures); } foreach (var tempPaintableTexture in tempPaintableTextures) { tempPaintableTexture.LocalMaskTexture = generatedTexture; } } if (onGenerated != null) { onGenerated.Invoke(generatedTexture); } return true; } return false; } protected virtual void OnEnable() { Generate(); } protected virtual void OnDisable() { Clear(); } } } #if UNITY_EDITOR namespace PaintIn3D { using UnityEditor; using TARGET = P3dGenerateMask; [CanEditMultipleObjects] [CustomEditor(typeof(TARGET))] public class P3dGenerateMask_Editor : CwEditor { protected override void OnInspector() { TARGET tgt; TARGET[] tgts; GetTargets(out tgt, out tgts); BeginError(Any(tgts, t => t.Mesh == null)); Draw("mesh", "The mask will be generated from this mesh."); EndError(); Draw("submesh", "The mask will be generated from this submesh of the mesh."); Draw("coord", "The texture channel of the mesh the mask will be generated from."); Draw("size", "The size of the generated texture."); Draw("format", "The format of the generated texture."); Draw("applyTo", "Should the generated mask be automatically applied?\n\nManually = Use the OnGenerated event to apply the mask to specific components.\n\nSiblings = The mask will be applied to all P3dPaintableTexture components on this GameObject.\n\nSiblingsAndDescendants = Like Siblings, but also all child GameObjects."); BeginDisabled(); EditorGUI.ObjectField(Reserve(18), new GUIContent("Generated Texture", "This allows you to access the generated texture."), tgt.GeneratedTexture, typeof(Texture), false); EndDisabled(); Separator(); Draw("onGenerated"); } } } #endif