AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
CompoundButtonIcon.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using HoloToolkit.Unity;
5 using System.Collections;
6 using UnityEngine;
7 
8 namespace HoloToolkit.Unity.Buttons
9 {
10  [ExecuteInEditMode]
11  [RequireComponent(typeof(CompoundButton))]
12  public class CompoundButtonIcon : ProfileButtonBase<ButtonIconProfile>
13  {
14  [Header("Icon Settings")]
15  [SerializeField]
16  [DropDownComponent]
17  private MeshRenderer targetIconRenderer = null;
18 
19  [Tooltip("Turns off the icon entirely")]
20  public bool DisableIcon = false;
21 
22  [Tooltip("Disregard the icon in the profile and use Icon Override instead")]
23  public bool OverrideIcon = false;
24 
25  [SerializeField]
27  private string iconName;
28 
29  [SerializeField]
30  [ShowIfBoolValue("OverrideIcon")]
31  [Tooltip("Icon to use for override")]
32  private Texture2D iconOverride = null;
33 
34  [SerializeField]
35  [Tooltip("Alpha value for the text mesh component")]
36  private float alpha = 1f;
37 
38  private Material instantiatedMaterial;
39  private Mesh instantiatedMesh;
40  private bool updatingAlpha = false;
41  private float alphaTarget = 1f;
42 
43  private const float AlphaThreshold = 0.01f;
44 
49  public float Alpha
50  {
51  get
52  {
53  return alphaTarget;
54  }
55  set
56  {
57  if (alphaTarget != value)
58  {
59  alphaTarget = value;
60  if (Application.isPlaying)
61  {
62  if (Mathf.Abs (alpha - alphaTarget) < AlphaThreshold)
63  {
64  return;
65  }
66 
67  if (updatingAlpha)
68  {
69  return;
70  }
71 
72  if (gameObject.activeSelf && gameObject.activeInHierarchy)
73  {
74  // Update over time
75  updatingAlpha = true;
76  StartCoroutine(UpdateAlpha());
77  }
78  else
79  {
80  // If we're not active, just set the alpha immediately
81  alpha = alphaTarget;
82  RefreshAlpha();
83  }
84  }
85  else
86  {
87  alphaTarget = value;
88  alpha = alphaTarget;
89  RefreshAlpha();
90  }
91  }
92  }
93  }
94 
95  public MeshFilter IconMeshFilter
96  {
97  get
98  {
99  return targetIconRenderer != null ? targetIconRenderer.GetComponent<MeshFilter>() : null;
100  }
101  }
102 
103  #if UNITY_EDITOR
104  public void OnWillSaveScene()
109  {
110  ClearInstancedAssets();
111 
112  SetIconName(iconName);
113 
114  }
115  #endif
116 
117  public string IconName
118  {
119  get
120  {
121  return iconName;
122  }
123  set
124  {
125  SetIconName(value);
126  }
127  }
128 
129  private void SetIconName(string newName)
130  {
131  // Avoid exploding if possible
132  if (Profile == null) {
133  return;
134  }
135 
136  if (targetIconRenderer == null) {
137  return;
138  }
139 
140  if (DisableIcon) {
141  targetIconRenderer.enabled = false;
142  return;
143  }
144 
145  if (Profile.IconMaterial == null || Profile.IconMesh == null) {
146  return;
147  }
148 
149  // Instantiate our local material now, if we don't have one
150  if (instantiatedMaterial == null)
151  {
152  instantiatedMaterial = new Material(Profile.IconMaterial);
153  instantiatedMaterial.name = Profile.IconMaterial.name;
154  }
155  targetIconRenderer.sharedMaterial = instantiatedMaterial;
156 
157  // Instantiate our local mesh now, if we don't have one
158  if (instantiatedMesh == null)
159  {
160  instantiatedMesh = Instantiate(Profile.IconMesh);
161  instantiatedMesh.name = Profile.IconMesh.name;
162  }
163  IconMeshFilter.sharedMesh = instantiatedMesh;
164 
165  if (OverrideIcon)
166  {
167  // Use the default mesh for override icons
168  targetIconRenderer.enabled = true;
169  IconMeshFilter.sharedMesh = Profile.IconMesh;
170  IconMeshFilter.transform.localScale = Vector3.one;
171  instantiatedMaterial.mainTexture = iconOverride;
172  return;
173  }
174 
175  // Disable the renderer if the name is empty
176  if (string.IsNullOrEmpty(newName))
177  {
178  targetIconRenderer.enabled = false;
179  iconName = newName;
180  return;
181  }
182 
183  // Moment of truth - try to get our icon
184  if (!Profile.GetIcon(newName, targetIconRenderer, IconMeshFilter, true))
185  {
186  targetIconRenderer.enabled = false;
187  return;
188  }
189 
190  // If we've made it this far we're golden
191  iconName = newName;
192  targetIconRenderer.enabled = true;
193  RefreshAlpha();
194  }
195 
196  private void OnDisable()
197  {
198  ClearInstancedAssets();
199  }
200 
201  private void OnEnable()
202  {
203  if (Application.isPlaying)
204  {
205  ClearInstancedAssets();
206  }
207 
208  SetIconName(iconName);
209  }
210 
211  private void Start()
212  {
213  SetIconName(iconName);
214  }
215 
216  private void RefreshAlpha()
217  {
218  string alphaColorProperty = string.IsNullOrEmpty(Profile.AlphaColorProperty) ? "_Color" : Profile.AlphaColorProperty;
219  if (instantiatedMaterial != null)
220  {
221  Color c = instantiatedMaterial.GetColor(alphaColorProperty);
222  c.a = alpha;
223  instantiatedMaterial.SetColor(alphaColorProperty, c);
224  }
225  }
226 
227  private void ClearInstancedAssets()
228  {
229  // Prevent material leaks
230  if (instantiatedMaterial != null)
231  {
232  if (Application.isPlaying)
233  {
234  Destroy(instantiatedMaterial);
235  }
236  else
237  {
238  DestroyImmediate(instantiatedMaterial);
239  }
240 
241  instantiatedMaterial = null;
242  }
243  if (instantiatedMesh != null)
244  {
245  if (Application.isPlaying)
246  {
247  Destroy(instantiatedMesh);
248  }
249  else
250  {
251  DestroyImmediate(instantiatedMesh);
252  }
253 
254  instantiatedMesh = null;
255  }
256 
257  // Reset to default mats and meshes
258  if (Profile != null)
259  {
260  if (targetIconRenderer != null)
261  {
262  // Restore the icon material to the renderer
263  targetIconRenderer.sharedMaterial = Profile.IconMaterial;
264  }
265  if (IconMeshFilter != null)
266  {
267  IconMeshFilter.sharedMesh = Profile.IconMesh;
268  }
269  }
270  // Reset our alpha to the alpha target
271  alpha = alphaTarget;
272  }
273 
274  private IEnumerator UpdateAlpha()
275  {
276  float startTime = Time.time;
277  Color color = Color.white;
278  string alphaColorProperty = string.IsNullOrEmpty(Profile.AlphaColorProperty) ? "_Color" : Profile.AlphaColorProperty;
279 
280  if (instantiatedMaterial != null)
281  {
282  color = instantiatedMaterial.GetColor(alphaColorProperty);
283  color.a = alpha;
284  }
285 
286  while (Time.time < startTime + Profile.AlphaTransitionSpeed)
287  {
288  alpha = Mathf.Lerp(alpha, alphaTarget, (Time.time - startTime) / Profile.AlphaTransitionSpeed);
289  if (instantiatedMaterial != null && !string.IsNullOrEmpty(alphaColorProperty))
290  {
291  color.a = alpha;
292  instantiatedMaterial.SetColor(alphaColorProperty, color);
293  }
294  yield return null;
295  }
296 
297  alpha = alphaTarget;
298  RefreshAlpha();
299  updatingAlpha = false;
300  }
301 
302 #if UNITY_EDITOR
303  [UnityEditor.CustomEditor(typeof(CompoundButtonIcon))]
304  public class CustomEditor : MRTKEditor {
305  protected override void DrawCustomFooter() {
306  CompoundButtonIcon iconButton = (CompoundButtonIcon)target;
307  if (iconButton != null && iconButton.Profile != null)
308  {
309  iconButton.IconName = iconButton.Profile.DrawIconSelectField(iconButton.iconName);
310  }
311 
312  }
313  }
314 #endif
315  }
316 }
Ensures a consistent profile field in compound buttons scripts which use a profile ...