Skip to content

Commit

Permalink
close #31; Mask interaction for each layer
Browse files Browse the repository at this point in the history
  • Loading branch information
mob-sakai committed Jan 31, 2019
1 parent a135ea1 commit 4e533c2
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 77 deletions.
134 changes: 134 additions & 0 deletions Scripts/Editor/SoftMaskableEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System;
using System.Reflection;
using Object = UnityEngine.Object;
using MaskIntr = UnityEngine.SpriteMaskInteraction;
using System.IO;

namespace Coffee.UIExtensions.Editors
Expand All @@ -17,6 +18,38 @@ namespace Coffee.UIExtensions.Editors
[CanEditMultipleObjects]
public class SoftMaskableEditor : Editor
{
//################################
// Constant or Static Members.
//################################
public enum MaskInteraction : int
{
VisibleInsideMask = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6),
VisibleOutsideMask = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6),
Custom = -1,
}

MaskInteraction maskInteraction
{
get
{
int value = _spMaskInteraction.intValue;
return _custom
? MaskInteraction.Custom
: System.Enum.IsDefined(typeof(MaskInteraction), value)
? (MaskInteraction)value
: MaskInteraction.Custom;
}
set
{
_custom = (value == MaskInteraction.Custom);
if (!_custom)
{
_spMaskInteraction.intValue = (int)value;
}
}
}
bool _custom = false;

static readonly Type s_TypeTMPro = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Text");
static readonly Type s_TypeTMP_SpriteAsset = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SpriteAsset");
static readonly Type s_TypeTMProSettings = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Settings");
Expand All @@ -36,9 +69,13 @@ public class SoftMaskableEditor : Editor
Shader _mobileShader;
Shader _spriteShader;
List<MaterialEditor> _materialEditors = new List<MaterialEditor> ();
SerializedProperty _spMaskInteraction;

private void OnEnable ()
{
_spMaskInteraction = serializedObject.FindProperty("m_MaskInteraction");
_custom = (maskInteraction == MaskInteraction.Custom);

ClearMaterialEditors ();

_shader = Shader.Find ("TextMeshPro/Distance Field (SoftMaskable)");
Expand All @@ -58,17 +95,114 @@ private void OnEnable ()
s_PiDefaultFontAssetPath = s_TypeTMProSettings.GetProperty ("defaultFontAssetPath", BindingFlags.Static | BindingFlags.Public);
s_PiDefaultSpriteAssetPath = s_TypeTMProSettings.GetProperty ("defaultSpriteAssetPath", BindingFlags.Static | BindingFlags.Public);
}

s_MaskWarning = new GUIContent(EditorGUIUtility.FindTexture("console.warnicon.sml"), "This component is not SoftMask. Use SoftMask instead of Mask.");
}

private void OnDisable ()
{
ClearMaterialEditors ();
}

List<Mask> tmpMasks = new List<Mask>();

void DrawMaskInteractions()
{
(target as SoftMaskable).GetComponentsInParent<Mask>(true, tmpMasks);
tmpMasks.RemoveAll(x => !x.enabled);
tmpMasks.Reverse();

maskInteraction = (MaskInteraction)EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction);
if (_custom)
{
var l = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 45;

using (var ccs = new EditorGUI.ChangeCheckScope())
{
int intr0 = DrawMaskInteraction(0);
int intr1 = DrawMaskInteraction(1);
int intr2 = DrawMaskInteraction(2);
int intr3 = DrawMaskInteraction(3);

if (ccs.changed) {
_spMaskInteraction.intValue = (intr0 << 0) + (intr1 << 2) + (intr2 << 4) + (intr3 << 6);
}
}

EditorGUIUtility.labelWidth = l;
}
}

static GUIContent s_MaskWarning = new GUIContent();

int DrawMaskInteraction(int layer)
{
Mask mask = layer < tmpMasks.Count ? tmpMasks[layer] : null;
MaskIntr intr = (MaskIntr)((_spMaskInteraction.intValue >> layer * 2) & 0x3);
if (!mask)
{
return (int)intr;
}

using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(mask is SoftMask ? GUIContent.none : s_MaskWarning, GUILayout.Width(16));
GUILayout.Space(-5);
EditorGUILayout.ObjectField("Mask " + layer, mask, typeof(Mask), false);
GUILayout.Space(-15);
return (int)(MaskIntr)EditorGUILayout.EnumPopup(intr);
}
}

public override void OnInspectorGUI ()
{
base.OnInspectorGUI ();

serializedObject.Update();
DrawMaskInteractions();

// maskInteraction = (MaskInteraction)EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction);
serializedObject.ApplyModifiedProperties();
/*
EditorGUI.indentLevel++;
var l = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 60;
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.ObjectField("Mask 0", null, typeof(Mask), false);
EditorGUILayout.EnumPopup (MaskIntr.None);
}
EditorGUIUtility.labelWidth = l;
EditorGUI.indentLevel--;
var spMaskInteraction = serializedObject.FindProperty ("m_MaskInteraction");
MaskIntr intr0 = (MaskIntr)((spMaskInteraction.intValue >> 0) & 0x3);
MaskIntr intr1 = (MaskIntr)((spMaskInteraction.intValue >> 2) & 0x3);
MaskIntr intr2 = (MaskIntr)((spMaskInteraction.intValue >> 4) & 0x3);
MaskIntr intr3 = (MaskIntr)((spMaskInteraction.intValue >> 6) & 0x3);
using (var ccs = new EditorGUI.ChangeCheckScope ()) {
intr0 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 0", intr0);
intr1 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 1", intr1);
intr2 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 2", intr2);
intr3 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 3", intr3);
if (ccs.changed) {
current.SetMaskInteractions (intr0,intr1,intr2,intr3);
}
}
*/

// spMaskInteraction.intValue = (intr0 << 0) | (intr1 << 2) | (intr2 << 4) | (intr3 << 6);
//
// serializedObject.ApplyModifiedProperties ();




// var current = target as SoftMaskable;
var current = target as SoftMaskable;
current.GetComponentsInChildren<Graphic> (true, s_Graphics);
var fixTargets = s_Graphics.Where (x => x.gameObject != current.gameObject && !x.GetComponent<SoftMaskable> () && (!x.GetComponent<Mask> () || x.GetComponent<Mask> ().showMaskGraphic)).ToList ();
Expand Down
89 changes: 48 additions & 41 deletions Scripts/SoftMask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Coffee.UIExtensions
/// Soft mask.
/// Use instead of Mask for smooth masking.
/// </summary>
public class SoftMask : Mask, IMeshModifier, ICanvasRaycastFilter
public class SoftMask : Mask, IMeshModifier
{
//################################
// Constant or Static Members.
Expand Down Expand Up @@ -106,7 +106,7 @@ public bool ignoreParent
{
m_IgnoreParent = value;
hasChanged = true;
OnTransformParentChanged ();
OnTransformParentChanged();
}
}
}
Expand All @@ -132,9 +132,9 @@ public RenderTexture softMaskBuffer
ReleaseRT(ref _softMaskBuffer);
}

if(!_softMaskBuffer)
if (!_softMaskBuffer)
{
_softMaskBuffer = RenderTexture.GetTemporary (w, h, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
_softMaskBuffer = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
hasChanged = true;
}

Expand All @@ -150,14 +150,23 @@ public bool hasChanged
}
private set
{
if(_parent)
if (_parent)
{
_parent.hasChanged = value;
}
_hasChanged = value;
}
}

public SoftMask parent
{
get
{
return _parent;
}
}


/// <summary>
/// Perform material modification in this function.
/// </summary>
Expand Down Expand Up @@ -203,34 +212,23 @@ void IMeshModifier.ModifyMesh(VertexHelper verts)
/// <param name="sp">Screen position.</param>
/// <param name="eventCamera">Raycast camera.</param>
/// <param name="g">Target graphic.</param>
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera, Graphic g)
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera, Graphic g, int[] interactions)
{
if (!isActiveAndEnabled || (g == graphic && !g.raycastTarget))
{
return true;
}
if (!RectTransformUtility.RectangleContainsScreenPoint(rectTransform, sp, eventCamera))
{
return false;
}

int x = (int)(softMaskBuffer.width * sp.x / Screen.width);
int y = (int)(softMaskBuffer.height * sp.y / Screen.height);
return 0.5f < GetPixelValue(x, y);
return 0.5f < GetPixelValue(x, y, interactions);
}

/// <summary>
/// Given a point and a camera is the raycast valid.
/// </summary>
/// <returns>Valid.</returns>
/// <param name="sp">Screen position.</param>
/// <param name="eventCamera">Raycast camera.</param>
public override bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
{
return IsRaycastLocationValid(sp, eventCamera, graphic);
return true;
}


//################################
// Protected Members.
//################################
Expand Down Expand Up @@ -329,12 +327,12 @@ protected override void OnTransformParentChanged()
hasChanged = true;
}

protected override void OnRectTransformDimensionsChange ()
protected override void OnRectTransformDimensionsChange()
{
hasChanged = true;
}

#if UNITY_EDITOR
#if UNITY_EDITOR
/// <summary>
/// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).
/// </summary>
Expand Down Expand Up @@ -382,13 +380,13 @@ static void UpdateMaskTextures()
continue;

var rt = sm.rectTransform;
if(rt.hasChanged)
if (rt.hasChanged)
{
rt.hasChanged = false;
sm.hasChanged = true;
}
#if UNITY_EDITOR
if(!Application.isPlaying)
if (!Application.isPlaying)
{
sm.hasChanged = true;
}
Expand All @@ -403,7 +401,7 @@ static void UpdateMaskTextures()
sm._hasChanged = false;
if (!sm._parent)
{
sm.UpdateMaskTexture ();
sm.UpdateMaskTexture();
}
}
}
Expand All @@ -413,13 +411,12 @@ static void UpdateMaskTextures()
/// </summary>
void UpdateMaskTexture()
{
if(!graphic || !graphic.canvas)
if (!graphic || !graphic.canvas)
{
return;
}

Transform stopAfter = MaskUtilities.FindRootSortOverrideCanvas(transform);
_stencilDepth = MaskUtilities.GetStencilDepth(transform, stopAfter);
_stencilDepth = MaskUtilities.GetStencilDepth(transform, MaskUtilities.FindRootSortOverrideCanvas(transform));

// Collect children soft masks.
int depth = 0;
Expand Down Expand Up @@ -448,9 +445,9 @@ void UpdateMaskTexture()
else
{
var pos = c.transform.localPosition;
var vm = Matrix4x4.TRS (-pos, Quaternion.identity, new Vector3 (1, 1, -1f));
var pm = Matrix4x4.TRS (new Vector3 (0, 0, -1), Quaternion.identity, new Vector3 (1 / pos.x, 1 / pos.y, -2 / 1000f));
_cb.SetViewProjectionMatrices (vm, pm);
var vm = Matrix4x4.TRS(-pos, Quaternion.identity, new Vector3(1, 1, -1f));
var pm = Matrix4x4.TRS(new Vector3(0, 0, -1), Quaternion.identity, new Vector3(1 / pos.x, 1 / pos.y, -2 / 1000f));
_cb.SetViewProjectionMatrices(vm, pm);
}

// Draw soft masks.
Expand All @@ -461,6 +458,11 @@ void UpdateMaskTexture()
{
var sm = s_TmpSoftMasks[i][j];

if (i != 0)
{
sm._stencilDepth = MaskUtilities.GetStencilDepth(sm.transform, MaskUtilities.FindRootSortOverrideCanvas(sm.transform));
}

// Set material property.
sm.material.SetInt(s_ColorMaskId, (int)1 << (3 - _stencilDepth - i));
sm._mpb.SetTexture(s_MainTexId, sm.graphic.mainTexture);
Expand Down Expand Up @@ -562,7 +564,7 @@ void SetParent(SoftMask newParent)
/// <summary>
/// Gets the pixel value.
/// </summary>
float GetPixelValue(int x, int y)
float GetPixelValue(int x, int y, int[] interactions)
{
if (!s_ReadTexture)
{
Expand All @@ -576,18 +578,23 @@ float GetPixelValue(int x, int y)
RenderTexture.active = currentRT;

var colors = s_ReadTexture.GetRawTextureData();

for (int i = 0; i < 4; i++)
{
switch (interactions[(i + 3)%4])
{
case 0: colors[i] = 255; break;
case 2: colors[i] = (byte)(255 - colors[i]); break;
}
}

switch (_stencilDepth)
{
case 0:
return (colors[1] / 255f);
case 1:
return (colors[1] / 255f) * (colors[2] / 255f);
case 2:
return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f);
case 3:
return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f) * (colors[0] / 255f);
default:
return 0;
case 0: return (colors[1] / 255f);
case 1: return (colors[1] / 255f) * (colors[2] / 255f);
case 2: return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f);
case 3: return (colors[1] / 255f) * (colors[2] / 255f) * (colors[3] / 255f) * (colors[0] / 255f);
default: return 0;
}
}
}
Expand Down
Loading

0 comments on commit 4e533c2

Please sign in to comment.