using System.Collections; using System.Collections.Generic; using UnityEngine; namespace UnityEditor.Experimental.VFX.Toolbox { /// /// An Editor UI Canvas that enables previsualizing an image. Derive from this class to implement your own. /// public abstract class VFXToolboxCanvas { internal Rect displayRect { get { return m_Rect; } set { m_Rect = value; } } internal bool maskR { get { return m_Material.GetColor("_RGBAMask").r == 1.0f; } set { Color c = m_Material.GetColor("_RGBAMask"); if (value) c.r = 1.0f; else c.r = 0.0f; m_Material.SetColor("_RGBAMask", c); Invalidate(true); } } internal bool maskG { get { return m_Material.GetColor("_RGBAMask").g == 1.0f; } set { Color c = m_Material.GetColor("_RGBAMask"); if (value) c.g = 1.0f; else c.g = 0.0f; m_Material.SetColor("_RGBAMask", c); Invalidate(true); } } internal bool maskB { get { return m_Material.GetColor("_RGBAMask").b == 1.0f; } set { Color c = m_Material.GetColor("_RGBAMask"); if (value) c.b = 1.0f; else c.b = 0.0f; m_Material.SetColor("_RGBAMask", c); Invalidate(true); } } internal bool maskA { get { return m_Material.GetColor("_RGBAMask").a == 1.0f; } set { Color c = m_Material.GetColor("_RGBAMask"); if (value) c.a = 1.0f; else c.a = 0.0f; m_Material.SetColor("_RGBAMask", c); Invalidate(true); } } internal bool filter { get { return m_bFilter; } set { if(m_bFilter!=value) { m_bFilter = value; InvalidateRenderTarget(); } } } internal int mipMap { get { return m_MipMap; } set { if(m_MipMap != value) { m_MipMap = value; m_Material.SetFloat("_MipMap", (float)value); InvalidateRenderTarget(); } else { m_MipMap = value; } } } internal int mipMapCount { get { return GetMipMapCount(); } } internal bool showGrid { get { return m_bShowGrid; } set { m_bShowGrid = value; } } internal float BackgroundBrightness { get { return m_bgBrightness; } set { SetBGBrightness(value); } } internal Styles styles { get { if (m_Styles == null) m_Styles = new Styles(this); return m_Styles; } } /// /// The current Zoom Level /// public float zoom { get { return m_Zoom; } set { m_Zoom = value; Invalidate(false); } } private Vector2 m_CameraPosition = Vector2.zero; private float m_Zoom = 1.0f; private bool m_DragPreview = false; private bool m_ZoomPreview = false; private Vector2 m_ZoomPreviewCenter; private Vector2 m_PreviousMousePosition; private Styles m_Styles; private Vector2 m_ZoomMinMax = new Vector2(0.2f, 10.0f); private bool m_bFilter = true; private int m_MipMap = 0; private bool m_bShowGrid = true; private Rect m_Rect; private Shader m_Shader; private Material m_Material; private RenderTexture m_RenderTexture; private bool m_IsDirtyRenderTarget; private bool m_bNeedRedraw; private float m_bgBrightness = -1.0f; /// /// The currently previewed Texture /// public Texture texture { get { return GetTexture(); } set { SetTexture(value); } } private Texture m_Texture; internal event CanvasGUIDelegate onCanvasGUI; internal delegate void CanvasGUIDelegate(); internal VFXToolboxCanvas(Rect displayRect, string shaderName = "Packages/com.unity.vfx-toolbox/Editor/Common/Canvas/Shaders/VFXToolboxCanvas.shader") { m_Rect = displayRect; m_IsDirtyRenderTarget = true; m_bNeedRedraw = true; m_Shader = AssetDatabase.LoadAssetAtPath(shaderName); m_Material = new Material(m_Shader) { hideFlags = HideFlags.DontSave }; m_RenderTexture = RenderTexture.GetTemporary(1,1,0); } internal virtual void Invalidate(bool needRedraw) { m_bNeedRedraw = m_bNeedRedraw | needRedraw; } /// /// Handle Setting the Texture to the canvas /// /// The texture to display protected abstract void SetTexture(Texture tex); /// /// Handle Getting the Texture displayed on the canvas /// /// The displayed texture protected abstract Texture GetTexture(); /// /// Returns the count of the currently set texture /// /// protected virtual int GetMipMapCount() { if (texture != null) { if (texture is Texture2D) { return (texture as Texture2D).mipmapCount; } else return 0; } else return 0; } internal void InvalidateRenderTarget() { m_IsDirtyRenderTarget = true; } internal void UpdateRenderTarget() { int width = Mathf.Max(1, texture.width / (int)Mathf.Pow(2, (mipMap))); int height = Mathf.Max(1, texture.height / (int)Mathf.Pow(2, (mipMap))); if(m_RenderTexture.width != width || m_RenderTexture.height != height) { RenderTexture.ReleaseTemporary(m_RenderTexture); m_RenderTexture = RenderTexture.GetTemporary(width,height,0,RenderTextureFormat.ARGBHalf); } if (filter) m_RenderTexture.filterMode = FilterMode.Bilinear; else m_RenderTexture.filterMode = FilterMode.Point; m_IsDirtyRenderTarget = false; Invalidate(true); } internal void Recenter(bool Refit) { m_CameraPosition = Vector2.zero; if(Refit) { float hZoom = (m_Rect.height - 70) / texture.height; float wZoom = (m_Rect.width - 70) / texture.width; m_Zoom = Mathf.Min(hZoom, wZoom); } else { m_Zoom = 1.0f; } } private void Zoom(float ZoomDelta, Vector2 zoomCenter) { Vector2 centerPos = - new Vector2(zoomCenter.x - m_Rect.width / 2, zoomCenter.y - m_Rect.height / 2) - m_CameraPosition; float prevZoom = m_Zoom; m_Zoom -= ZoomDelta; if(m_Zoom < m_ZoomMinMax.x) m_Zoom = m_ZoomMinMax.x; else if(m_Zoom > m_ZoomMinMax.y) m_Zoom = m_ZoomMinMax.y; else { m_CameraPosition += centerPos - ((m_Zoom / prevZoom) * centerPos); } } /// /// Handles common Keyboard events to perform navigation /// protected virtual void HandleKeyboardEvents() { if(Event.current.type == EventType.KeyDown) { switch(Event.current.keyCode) { // Viewport Toggles case KeyCode.F: Recenter(!Event.current.shift); break; case KeyCode.G: showGrid = !showGrid; break; case KeyCode.J: filter = !filter; Invalidate(true); break; // Brightness Control case KeyCode.V: BrightnessDown(0.1f); break; case KeyCode.B: ResetBrightness(); break; case KeyCode.N: BrightnessUp(0.1f); break; default: return; // Return without using event. } Invalidate(false); Event.current.Use(); } } private void DrawCurrentTexture() { Rect rect = new Rect(0, 0, m_Rect.width, m_Rect.height); // Pan : use Middle Mouse button or Alt+Click if(Event.current.type == EventType.MouseDown && (Event.current.button == 2 || (Event.current.button == 0 && Event.current.alt))) { m_DragPreview = true; } if((Event.current.rawType == EventType.MouseUp || Event.current.rawType == EventType.DragExited) && (Event.current.button == 2 || Event.current.button == 0)) { m_DragPreview = false; Invalidate(false); } if((!m_DragPreview && Event.current.alt) || m_DragPreview) { EditorGUIUtility.AddCursorRect(rect, MouseCursor.Pan); Invalidate(false); } if(m_DragPreview && Event.current.type == EventType.MouseDrag) { m_CameraPosition -= Event.current.delta; Invalidate(false); } // Zoom : using MouseWheel if (Event.current.type == EventType.ScrollWheel && rect.Contains(Event.current.mousePosition) ) { // Delta negative when zooming In, Positive when zooming out Zoom(Event.current.delta.y * 0.05f, Event.current.mousePosition); Invalidate(false); } // Zoom : using Alt + RightClick if (Event.current.type == EventType.MouseDown && Event.current.button == 1 && Event.current.alt) { m_ZoomPreview = true; m_ZoomPreviewCenter = Event.current.mousePosition; m_PreviousMousePosition = m_ZoomPreviewCenter; } if (Event.current.rawType == EventType.MouseUp && Event.current.button == 1) { m_ZoomPreview = false; } if(m_ZoomPreview) { EditorGUIUtility.AddCursorRect(rect, MouseCursor.Zoom); Vector2 mouseDelta = Event.current.mousePosition - m_PreviousMousePosition; Zoom((mouseDelta.x + mouseDelta.y) * -0.002f, m_ZoomPreviewCenter); Invalidate(false); m_PreviousMousePosition = Event.current.mousePosition; } // Draw Texture if(Event.current.type == EventType.Repaint) { GUI.DrawTexture ( new Rect( (rect.width/2) - m_CameraPosition.x - (texture.width*m_Zoom*0.5f), (rect.height/2) - m_CameraPosition.y - (texture.height*m_Zoom*0.5f), texture.width*m_Zoom, texture.height*m_Zoom ), m_RenderTexture, ScaleMode.ScaleToFit ); } } /// /// Helper Function that converts a Canvas Position to a Screen Position based on the current Canvas Position and Zoom /// /// Position in Canvas Space /// Position in Screen Space public Vector2 CanvasToScreen(Vector2 Position) { return new Vector2( (m_Rect.width / 2) - m_CameraPosition.x - (Position.x * m_Zoom), (m_Rect.height / 2) - m_CameraPosition.y - (Position.y * m_Zoom) ); } /// /// Draws a line grid around the texture /// protected virtual void DrawGrid() { Vector2 src, dst; if(BackgroundBrightness < 0.5f) Handles.color = new Color(1.0f,1.0f,1.0f,0.33333f); else Handles.color = new Color(0.0f,0.0f,0.0f,0.66666f); src = CanvasToScreen(new Vector2(-texture.width/2, -texture.height/2)); dst = CanvasToScreen(new Vector2(texture.width/2, texture.height/2)); Handles.DrawLine(new Vector2(src.x,src.y), new Vector2(dst.x,src.y)); Handles.DrawLine(new Vector2(dst.x,src.y), new Vector2(dst.x,dst.y)); Handles.DrawLine(new Vector2(dst.x,dst.y), new Vector2(src.x,dst.y)); Handles.DrawLine(new Vector2(src.x,dst.y), new Vector2(src.x,src.y)); Handles.color = Color.white; } private void BlitIntoRenderTarget() { // Backup GUI RenderTarget var oldrendertarget = RenderTexture.active; Graphics.Blit(texture, m_RenderTexture, m_Material); // Restore GUI RenderTarget RenderTexture.active = oldrendertarget; } internal virtual void OnGUI() { if(m_bgBrightness < 0.0f) { ResetBrightness(); } // Focus taken when clicked in viewport if (Event.current.type == EventType.MouseDown && m_Rect.Contains(Event.current.mousePosition)) { GUI.FocusControl(""); } if(texture != null && Event.current.type == EventType.Repaint) { if (m_IsDirtyRenderTarget) UpdateRenderTarget(); if(m_bNeedRedraw) { BlitIntoRenderTarget(); m_bNeedRedraw = false; } } GUI.BeginGroup(m_Rect); Rect LocalRect = new Rect(Vector2.zero, m_Rect.size); #if !UNITY_2018_2_OR_NEWER GL.sRGBWrite = (QualitySettings.activeColorSpace == ColorSpace.Linear); #endif GUI.DrawTextureWithTexCoords(LocalRect, BackgroundTexture, new Rect(0, 0, m_Rect.width / 64, m_Rect.height / 64)); #if !UNITY_2018_2_OR_NEWER //GL.sRGBWrite = false; #endif if (texture != null) { HandleKeyboardEvents(); #if !UNITY_2018_2_OR_NEWER GL.sRGBWrite = (QualitySettings.activeColorSpace == ColorSpace.Linear); #endif DrawCurrentTexture(); #if !UNITY_2018_2_OR_NEWER //GL.sRGBWrite = false; #endif if (showGrid) DrawGrid(); if (onCanvasGUI != null) onCanvasGUI(); } else GUI.Label(LocalRect, VFXToolboxGUIUtility.Get("No Texture"), EditorStyles.centeredGreyMiniLabel); #if !UNITY_2018_2_OR_NEWER //GL.sRGBWrite = false; #endif GUI.EndGroup(); } #region BRIGHTNESS CONTROLS internal Texture2D BackgroundTexture { get { return m_BackgroundTexture; } } private Texture2D m_BackgroundTexture; internal void SetBGBrightness(float value) { m_bgBrightness = value; m_BackgroundTexture = Styles.GetBGTexture(value); } internal void ResetBrightness() { if (EditorGUIUtility.isProSkin) BackgroundBrightness = 0.2f; else BackgroundBrightness = 0.4f; } internal void BrightnessUp(float value) { BackgroundBrightness = Mathf.Min(BackgroundBrightness + value,1.0f); } internal void BrightnessDown(float value) { BackgroundBrightness = Mathf.Max(0.0f, BackgroundBrightness - value); } #endregion #region STYLES internal class Styles { public GUIStyle miniLabel { get { return m_Canvas.BackgroundBrightness < 0.5f ? m_ViewportMiniLabel : m_ViewportMiniLabelDark; } } public GUIStyle miniLabelRight { get { return m_Canvas.BackgroundBrightness < 0.5f ? m_ViewportMiniLabelRight : m_ViewportMiniLabelRightDark; } } public GUIStyle miniLabelCenter { get { return m_Canvas.BackgroundBrightness < 0.5f ? m_ViewportMiniLabelCenter : m_ViewportMiniLabelCenterDark; } } public GUIStyle label { get { return m_Canvas.BackgroundBrightness < 0.5f ? m_ViewportLabel : m_ViewportLabelDark; } } public GUIStyle largeLabel { get { return m_Canvas.BackgroundBrightness < 0.5f ? m_ViewportLargeLabel : m_ViewportLargeLabelDark; } } public Color backgroundPanelColor { get { return m_Canvas.BackgroundBrightness < 0.5f ? m_BackgroundPanelColor : m_BackgroundPanelColorDark; } } public Color red { get { return m_Canvas.BackgroundBrightness < 0.5f ? new Color(1, 0, 0, 1) : new Color(0.7f, 0, 0, 1); } } public Color green { get { return m_Canvas.BackgroundBrightness < 0.5f ? new Color(0, 1, 0, 1) : new Color(0, 0.5f, 0, 1); } } public Color blue { get { return m_Canvas.BackgroundBrightness < 0.5f ? new Color(0, 0, 1, 1) : new Color(0, 0, 0.5f, 1); } } public Color white { get { return m_Canvas.BackgroundBrightness < 0.5f ? new Color(1, 1, 1, 1) : new Color(0, 0, 0, 1); } } public Color black { get { return m_Canvas.BackgroundBrightness < 0.5f ? new Color(0, 0, 0, 1) : new Color(1, 1, 1, 1); } } public Color yellow { get { return m_Canvas.BackgroundBrightness < 0.5f ? new Color(1.0f, 0.8f, 0.25f) : new Color(0.5f, 0.4f, 0.1f); } } public Color cyan { get { return m_Canvas.BackgroundBrightness < 0.5f ? new Color(0.25f, 0.8f, 1.0f) : new Color(0.1f, 0.4f, 0.5f); } } public Color fadewhite { get { return m_Canvas.BackgroundBrightness < 0.5f ? new Color(1, 1, 1, 0.25f) : new Color(0, 0, 0, 0.25f); } } private GUIStyle m_ViewportMiniLabel; private GUIStyle m_ViewportMiniLabelDark; private GUIStyle m_ViewportMiniLabelRight; private GUIStyle m_ViewportMiniLabelRightDark; private GUIStyle m_ViewportMiniLabelCenter; private GUIStyle m_ViewportMiniLabelCenterDark; private GUIStyle m_ViewportLabel; private GUIStyle m_ViewportLabelDark; private GUIStyle m_ViewportLargeLabel; private GUIStyle m_ViewportLargeLabelDark; private VFXToolboxCanvas m_Canvas; private Color m_BackgroundPanelColor; private Color m_BackgroundPanelColorDark; public Styles(VFXToolboxCanvas canvas) { m_Canvas = canvas; m_ViewportMiniLabel = new GUIStyle(EditorStyles.miniLabel); m_ViewportMiniLabel.normal.textColor = Color.white; m_ViewportMiniLabelDark = new GUIStyle(EditorStyles.miniLabel); m_ViewportMiniLabelDark.normal.textColor = Color.black; m_ViewportMiniLabelRight = new GUIStyle(m_ViewportMiniLabel); m_ViewportMiniLabelRight.alignment = TextAnchor.MiddleRight; m_ViewportMiniLabelRightDark = new GUIStyle(m_ViewportMiniLabelDark); m_ViewportMiniLabelRightDark.alignment = TextAnchor.MiddleRight; m_ViewportMiniLabelCenter = new GUIStyle(m_ViewportMiniLabel); m_ViewportMiniLabelCenter.alignment = TextAnchor.MiddleCenter; m_ViewportMiniLabelCenterDark = new GUIStyle(m_ViewportMiniLabelDark); m_ViewportMiniLabelCenterDark.alignment = TextAnchor.MiddleCenter; m_ViewportLabel = new GUIStyle(EditorStyles.largeLabel); m_ViewportLabel.normal.textColor = Color.white; m_ViewportLabelDark = new GUIStyle(EditorStyles.largeLabel); m_ViewportLabelDark.normal.textColor = Color.black; m_ViewportLargeLabel = new GUIStyle(EditorStyles.largeLabel); m_ViewportLargeLabel.fontSize = 24; m_ViewportLargeLabel.normal.textColor = Color.white; m_ViewportLargeLabelDark = new GUIStyle(EditorStyles.largeLabel); m_ViewportLargeLabelDark.fontSize = 24; m_ViewportLargeLabelDark.normal.textColor = Color.black; m_BackgroundPanelColor = new Color(0.02f, 0.02f, 0.02f, 0.85f); m_BackgroundPanelColorDark = new Color(0.25f, 0.25f, 0.25f, 0.85f); } public static Texture2D GetBGTexture(float brightness) { Texture2D out_tex = new Texture2D(2, 2) { hideFlags = HideFlags.DontSave }; Color[] bgcolors = new Color[4]; brightness *= 0.95f; bgcolors[0] = new Color(brightness+0.05f, brightness+0.05f, brightness+0.05f); bgcolors[1] = new Color(brightness, brightness, brightness); bgcolors[2] = new Color(brightness, brightness, brightness); bgcolors[3] = new Color(brightness+0.05f, brightness+0.05f, brightness+0.05f); out_tex.SetPixels(bgcolors); out_tex.wrapMode = TextureWrapMode.Repeat; out_tex.filterMode = FilterMode.Point; out_tex.Apply(); return out_tex; } } #endregion } }