CinemachineScreenComposerGuides.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. using UnityEngine;
  2. using UnityEditor;
  3. using Cinemachine.Utility;
  4. #if UNITY_2019_2_OR_NEWER
  5. using UnityEngine.UIElements;
  6. #endif
  7. namespace Cinemachine.Editor
  8. {
  9. #if !UNITY_2019_2_OR_NEWER
  10. internal class GameViewEventCatcher
  11. {
  12. public void OnEnable() {}
  13. public void OnDisable() {}
  14. }
  15. #else
  16. // This is necessary because in 2019.3 we don't get mouse events in the game view in Edit mode
  17. internal class GameViewEventCatcher
  18. {
  19. class Dragger
  20. {
  21. bool mActive;
  22. VisualElement mRoot;
  23. void OnMouseDown(MouseDownEvent e) { if (mRoot.panel != null) mActive = true; }
  24. void OnMouseUp(MouseUpEvent e) { mActive = false; }
  25. void OnMouseMove(MouseMoveEvent e)
  26. {
  27. if (mActive && mRoot.panel != null)
  28. {
  29. if (!Application.isPlaying
  30. && CinemachineSettings.CinemachineCoreSettings.ShowInGameGuides
  31. && CinemachineBrain.SoloCamera == null)
  32. {
  33. InspectorUtility.RepaintGameView();
  34. }
  35. }
  36. }
  37. public Dragger(VisualElement root)
  38. {
  39. mRoot = root;
  40. if (mRoot == null || mRoot.panel == null || mRoot.panel.visualTree == null)
  41. return;
  42. mRoot.panel.visualTree.RegisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);
  43. mRoot.panel.visualTree.RegisterCallback<MouseUpEvent>(OnMouseUp, TrickleDown.TrickleDown);
  44. mRoot.panel.visualTree.RegisterCallback<MouseMoveEvent>(OnMouseMove, TrickleDown.TrickleDown);
  45. }
  46. public void Unregister()
  47. {
  48. if (mRoot == null || mRoot.panel == null || mRoot.panel.visualTree == null)
  49. return;
  50. mRoot.panel.visualTree.UnregisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);
  51. mRoot.panel.visualTree.UnregisterCallback<MouseUpEvent>(OnMouseUp, TrickleDown.TrickleDown);
  52. mRoot.panel.visualTree.UnregisterCallback<MouseMoveEvent>(OnMouseMove, TrickleDown.TrickleDown);
  53. }
  54. }
  55. Dragger[] mDraggers;
  56. // Create manipulator in each game view
  57. public void OnEnable()
  58. {
  59. System.Reflection.Assembly assembly = typeof(UnityEditor.EditorWindow).Assembly;
  60. System.Type type = assembly.GetType( "UnityEditor.GameView" );
  61. var gameViews = UnityEngine.Resources.FindObjectsOfTypeAll(type);
  62. mDraggers = new Dragger[gameViews.Length];
  63. for (int i = 0; i < gameViews.Length; ++i)
  64. {
  65. var gameViewRoot = (gameViews[i] as UnityEditor.EditorWindow).rootVisualElement;
  66. mDraggers[i] = new Dragger(gameViewRoot);
  67. }
  68. }
  69. public void OnDisable()
  70. {
  71. for (int i = 0; mDraggers != null && i < mDraggers.Length; ++i)
  72. {
  73. var dragger = mDraggers[i];
  74. if (dragger != null)
  75. dragger.Unregister();
  76. }
  77. mDraggers = null;
  78. }
  79. }
  80. #endif
  81. /// <summary>
  82. /// Use an instance of this class to draw screen composer guides in the game view.
  83. /// This is an internal class, and is not meant to be called outside of Cinemachine.
  84. /// </summary>
  85. public class CinemachineScreenComposerGuides
  86. {
  87. /// <summary>Delegate for getting the hard/soft guide rects</summary>
  88. /// <returns>The Hard/Soft guide rect</returns>
  89. public delegate Rect RectGetter();
  90. /// <summary>Delegate for setting the hard/soft guide rects</summary>
  91. /// <param name="rcam">The value to set</param>
  92. public delegate void RectSetter(Rect r);
  93. /// <summary>Delegate to get the current object whose guides are being drawn</summary>
  94. /// <returns>The target object whose guides are being drawn</returns>
  95. public delegate SerializedObject ObjectGetter();
  96. /// <summary>Get the Hard Guide. Client must implement this</summary>
  97. public RectGetter GetHardGuide;
  98. /// <summary>Get the Soft Guide. Client must implement this</summary>
  99. public RectGetter GetSoftGuide;
  100. /// <summary>Set the Hard Guide. Client must implement this</summary>
  101. public RectSetter SetHardGuide;
  102. /// <summary>Get the Soft Guide. Client must implement this</summary>
  103. public RectSetter SetSoftGuide;
  104. /// <summary>Get the target object whose guides are being drawn. Client must implement this</summary>
  105. public ObjectGetter Target;
  106. /// <summary>Width of the draggable guide bar in the game view</summary>
  107. public const float kGuideBarWidthPx = 3f;
  108. /// <summary>
  109. /// Helper to set the appropriate new rects in the target object, is something changed.
  110. /// </summary>
  111. /// <param name="oldHard">Current hard guide</param>
  112. /// <param name="oldSoft">Current soft guide</param>
  113. /// <param name="newHard">New hard guide</param>
  114. /// <param name="newSoft">New soft guide</param>
  115. public void SetNewBounds(Rect oldHard, Rect oldSoft, Rect newHard, Rect newSoft)
  116. {
  117. if ((oldSoft != newSoft) || (oldHard != newHard))
  118. {
  119. Undo.RecordObject(Target().targetObject, "Composer Bounds");
  120. if (oldSoft != newSoft)
  121. SetSoftGuide(newSoft);
  122. if (oldHard != newHard)
  123. SetHardGuide(newHard);
  124. Target().ApplyModifiedProperties();
  125. }
  126. }
  127. Rect GetCameraRect(Camera outputCamera, LensSettings lens)
  128. {
  129. Rect cameraRect = outputCamera.pixelRect;
  130. float screenHeight = cameraRect.height;
  131. float screenWidth = cameraRect.width;
  132. #if UNITY_2018_2_OR_NEWER
  133. float screenAspect = screenWidth / screenHeight;
  134. switch (outputCamera.gateFit)
  135. {
  136. case Camera.GateFitMode.Vertical:
  137. screenWidth = screenHeight * lens.Aspect;
  138. cameraRect.position += new Vector2((cameraRect.width - screenWidth) * 0.5f, 0);
  139. break;
  140. case Camera.GateFitMode.Horizontal:
  141. screenHeight = screenWidth / lens.Aspect;
  142. cameraRect.position += new Vector2(0, (cameraRect.height - screenHeight) * 0.5f);
  143. break;
  144. case Camera.GateFitMode.Overscan:
  145. if (screenAspect < lens.Aspect)
  146. {
  147. screenHeight = screenWidth / lens.Aspect;
  148. cameraRect.position += new Vector2(0, (cameraRect.height - screenHeight) * 0.5f);
  149. }
  150. else
  151. {
  152. screenWidth = screenHeight * lens.Aspect;
  153. cameraRect.position += new Vector2((cameraRect.width - screenWidth) * 0.5f, 0);
  154. }
  155. break;
  156. case Camera.GateFitMode.Fill:
  157. if (screenAspect > lens.Aspect)
  158. {
  159. screenHeight = screenWidth / lens.Aspect;
  160. cameraRect.position += new Vector2(0, (cameraRect.height - screenHeight) * 0.5f);
  161. }
  162. else
  163. {
  164. screenWidth = screenHeight * lens.Aspect;
  165. cameraRect.position += new Vector2((cameraRect.width - screenWidth) * 0.5f, 0);
  166. }
  167. break;
  168. case Camera.GateFitMode.None:
  169. break;
  170. }
  171. #endif
  172. cameraRect = new Rect(cameraRect.position, new Vector2(screenWidth, screenHeight));
  173. // Invert Y
  174. float h = cameraRect.height;
  175. cameraRect.yMax = Screen.height - cameraRect.yMin;
  176. cameraRect.yMin = cameraRect.yMax - h;
  177. // Shift the guides along with the lens
  178. cameraRect.position += new Vector2(
  179. -screenWidth * lens.LensShift.x, screenHeight * lens.LensShift.y);
  180. return cameraRect;
  181. }
  182. /// <summary>
  183. /// Call this from the inspector's OnGUI. Draws the guides and manages dragging.
  184. /// </summary>
  185. /// <param name="isLive">Is the target live</param>
  186. /// <param name="outputCamera">Destination camera</param>
  187. /// <param name="lens">Current lens settings</param>
  188. /// <param name="showHardGuides">True if hard guides should be shown</param>
  189. public void OnGUI_DrawGuides(bool isLive, Camera outputCamera, LensSettings lens, bool showHardGuides)
  190. {
  191. Rect cameraRect = GetCameraRect(outputCamera, lens);
  192. float screenWidth = cameraRect.width;
  193. float screenHeight = cameraRect.height;
  194. // Rotate the guides along with the dutch
  195. Matrix4x4 oldMatrix = GUI.matrix;
  196. GUI.matrix = Matrix4x4.Translate(cameraRect.min);
  197. GUIUtility.RotateAroundPivot(lens.Dutch, cameraRect.center);
  198. Color hardBarsColour = CinemachineSettings.ComposerSettings.HardBoundsOverlayColour;
  199. Color softBarsColour = CinemachineSettings.ComposerSettings.SoftBoundsOverlayColour;
  200. float overlayOpacity = CinemachineSettings.ComposerSettings.OverlayOpacity;
  201. if (!isLive)
  202. {
  203. softBarsColour = CinemachineSettings.CinemachineCoreSettings.InactiveGizmoColour;
  204. hardBarsColour = Color.Lerp(softBarsColour, Color.black, 0.5f);
  205. overlayOpacity /= 2;
  206. }
  207. hardBarsColour.a *= overlayOpacity;
  208. softBarsColour.a *= overlayOpacity;
  209. Rect r = showHardGuides ? GetHardGuide() : new Rect(-2, -2, 4, 4);
  210. float hardEdgeLeft = r.xMin * screenWidth;
  211. float hardEdgeTop = r.yMin * screenHeight;
  212. float hardEdgeRight = r.xMax * screenWidth;
  213. float hardEdgeBottom = r.yMax * screenHeight;
  214. mDragBars[(int)DragBar.HardBarLineLeft] = new Rect(hardEdgeLeft - kGuideBarWidthPx / 2f, 0f, kGuideBarWidthPx, screenHeight);
  215. mDragBars[(int)DragBar.HardBarLineTop] = new Rect(0f, hardEdgeTop - kGuideBarWidthPx / 2f, screenWidth, kGuideBarWidthPx);
  216. mDragBars[(int)DragBar.HardBarLineRight] = new Rect(hardEdgeRight - kGuideBarWidthPx / 2f, 0f, kGuideBarWidthPx, screenHeight);
  217. mDragBars[(int)DragBar.HardBarLineBottom] = new Rect(0f, hardEdgeBottom - kGuideBarWidthPx / 2f, screenWidth, kGuideBarWidthPx);
  218. r = GetSoftGuide();
  219. float softEdgeLeft = r.xMin * screenWidth;
  220. float softEdgeTop = r.yMin * screenHeight;
  221. float softEdgeRight = r.xMax * screenWidth;
  222. float softEdgeBottom = r.yMax * screenHeight;
  223. mDragBars[(int)DragBar.SoftBarLineLeft] = new Rect(softEdgeLeft - kGuideBarWidthPx / 2f, 0f, kGuideBarWidthPx, screenHeight);
  224. mDragBars[(int)DragBar.SoftBarLineTop] = new Rect(0f, softEdgeTop - kGuideBarWidthPx / 2f, screenWidth, kGuideBarWidthPx);
  225. mDragBars[(int)DragBar.SoftBarLineRight] = new Rect(softEdgeRight - kGuideBarWidthPx / 2f, 0f, kGuideBarWidthPx, screenHeight);
  226. mDragBars[(int)DragBar.SoftBarLineBottom] = new Rect(0f, softEdgeBottom - kGuideBarWidthPx / 2f, screenWidth, kGuideBarWidthPx);
  227. mDragBars[(int)DragBar.Center] = new Rect(softEdgeLeft, softEdgeTop, softEdgeRight - softEdgeLeft, softEdgeBottom - softEdgeTop);
  228. // Handle dragging bars
  229. if (isLive)
  230. OnGuiHandleBarDragging(screenWidth, screenHeight);
  231. // Draw the masks
  232. GUI.color = hardBarsColour;
  233. Rect hardBarLeft = new Rect(0, hardEdgeTop, Mathf.Max(0, hardEdgeLeft), hardEdgeBottom - hardEdgeTop);
  234. Rect hardBarRight = new Rect(hardEdgeRight, hardEdgeTop,
  235. Mathf.Max(0, screenWidth - hardEdgeRight), hardEdgeBottom - hardEdgeTop);
  236. Rect hardBarTop = new Rect(Mathf.Min(0, hardEdgeLeft), 0,
  237. Mathf.Max(screenWidth, hardEdgeRight) - Mathf.Min(0, hardEdgeLeft), Mathf.Max(0, hardEdgeTop));
  238. Rect hardBarBottom = new Rect(Mathf.Min(0, hardEdgeLeft), hardEdgeBottom,
  239. Mathf.Max(screenWidth, hardEdgeRight) - Mathf.Min(0, hardEdgeLeft),
  240. Mathf.Max(0, screenHeight - hardEdgeBottom));
  241. GUI.DrawTexture(hardBarLeft, Texture2D.whiteTexture, ScaleMode.StretchToFill);
  242. GUI.DrawTexture(hardBarTop, Texture2D.whiteTexture, ScaleMode.StretchToFill);
  243. GUI.DrawTexture(hardBarRight, Texture2D.whiteTexture, ScaleMode.StretchToFill);
  244. GUI.DrawTexture(hardBarBottom, Texture2D.whiteTexture, ScaleMode.StretchToFill);
  245. GUI.color = softBarsColour;
  246. Rect softBarLeft = new Rect(hardEdgeLeft, softEdgeTop, softEdgeLeft - hardEdgeLeft, softEdgeBottom - softEdgeTop);
  247. Rect softBarTop = new Rect(hardEdgeLeft, hardEdgeTop, hardEdgeRight - hardEdgeLeft, softEdgeTop - hardEdgeTop);
  248. Rect softBarRight = new Rect(softEdgeRight, softEdgeTop, hardEdgeRight - softEdgeRight, softEdgeBottom - softEdgeTop);
  249. Rect softBarBottom = new Rect(hardEdgeLeft, softEdgeBottom, hardEdgeRight - hardEdgeLeft, hardEdgeBottom - softEdgeBottom);
  250. GUI.DrawTexture(softBarLeft, Texture2D.whiteTexture, ScaleMode.StretchToFill);
  251. GUI.DrawTexture(softBarTop, Texture2D.whiteTexture, ScaleMode.StretchToFill);
  252. GUI.DrawTexture(softBarRight, Texture2D.whiteTexture, ScaleMode.StretchToFill);
  253. GUI.DrawTexture(softBarBottom, Texture2D.whiteTexture, ScaleMode.StretchToFill);
  254. // Draw the drag bars
  255. GUI.DrawTexture(mDragBars[(int)DragBar.SoftBarLineLeft], Texture2D.whiteTexture, ScaleMode.StretchToFill);
  256. GUI.DrawTexture(mDragBars[(int)DragBar.SoftBarLineTop], Texture2D.whiteTexture, ScaleMode.StretchToFill);
  257. GUI.DrawTexture(mDragBars[(int)DragBar.SoftBarLineRight], Texture2D.whiteTexture, ScaleMode.StretchToFill);
  258. GUI.DrawTexture(mDragBars[(int)DragBar.SoftBarLineBottom], Texture2D.whiteTexture, ScaleMode.StretchToFill);
  259. GUI.color = hardBarsColour;
  260. GUI.DrawTexture(mDragBars[(int)DragBar.HardBarLineLeft], Texture2D.whiteTexture, ScaleMode.StretchToFill);
  261. GUI.DrawTexture(mDragBars[(int)DragBar.HardBarLineTop], Texture2D.whiteTexture, ScaleMode.StretchToFill);
  262. GUI.DrawTexture(mDragBars[(int)DragBar.HardBarLineRight], Texture2D.whiteTexture, ScaleMode.StretchToFill);
  263. GUI.DrawTexture(mDragBars[(int)DragBar.HardBarLineBottom], Texture2D.whiteTexture, ScaleMode.StretchToFill);
  264. GUI.matrix = oldMatrix;
  265. }
  266. // For dragging the bars - order defines precedence
  267. private enum DragBar
  268. {
  269. Center,
  270. SoftBarLineLeft, SoftBarLineTop, SoftBarLineRight, SoftBarLineBottom,
  271. HardBarLineLeft, HardBarLineTop, HardBarLineRight, HardBarLineBottom,
  272. NONE
  273. };
  274. private DragBar mDragging = DragBar.NONE;
  275. private Rect[] mDragBars = new Rect[9];
  276. private void OnGuiHandleBarDragging(float screenWidth, float screenHeight)
  277. {
  278. if (Event.current.type == EventType.MouseUp)
  279. mDragging = DragBar.NONE;
  280. if (Event.current.type == EventType.MouseDown)
  281. {
  282. mDragging = DragBar.NONE;
  283. for (DragBar i = DragBar.Center; i < DragBar.NONE && mDragging == DragBar.NONE; ++i)
  284. {
  285. Vector2 slop = new Vector2(5f, 5f);
  286. if (i == DragBar.Center)
  287. {
  288. if (mDragBars[(int)i].width > 3f * slop.x)
  289. slop.x = -slop.x;
  290. if (mDragBars[(int)i].height > 3f * slop.y)
  291. slop.y = -slop.y;
  292. }
  293. Rect r = mDragBars[(int)i].Inflated(slop);
  294. if (r.Contains(Event.current.mousePosition))
  295. mDragging = i;
  296. }
  297. }
  298. if (mDragging != DragBar.NONE && Event.current.type == EventType.MouseDrag)
  299. {
  300. Vector2 d = new Vector2(
  301. Event.current.delta.x / screenWidth,
  302. Event.current.delta.y / screenHeight);
  303. // First snapshot some settings
  304. Rect newHard = GetHardGuide();
  305. Rect newSoft = GetSoftGuide();
  306. Vector2 changed = Vector2.zero;
  307. switch (mDragging)
  308. {
  309. case DragBar.Center: newSoft.position += d; break;
  310. case DragBar.SoftBarLineLeft: newSoft = newSoft.Inflated(new Vector2(-d.x, 0)); break;
  311. case DragBar.SoftBarLineRight: newSoft = newSoft.Inflated(new Vector2(d.x, 0)); break;
  312. case DragBar.SoftBarLineTop: newSoft = newSoft.Inflated(new Vector2(0, -d.y)); break;
  313. case DragBar.SoftBarLineBottom: newSoft = newSoft.Inflated(new Vector2(0, d.y)); break;
  314. case DragBar.HardBarLineLeft: newHard = newHard.Inflated(new Vector2(-d.x, 0)); break;
  315. case DragBar.HardBarLineRight: newHard = newHard.Inflated(new Vector2(d.x, 0)); break;
  316. case DragBar.HardBarLineBottom: newHard = newHard.Inflated(new Vector2(0, d.y)); break;
  317. case DragBar.HardBarLineTop: newHard = newHard.Inflated(new Vector2(0, -d.y)); break;
  318. }
  319. // Apply the changes, enforcing the bounds
  320. SetNewBounds(GetHardGuide(), GetSoftGuide(), newHard, newSoft);
  321. Event.current.Use();
  322. }
  323. }
  324. }
  325. }