GameWindow.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using BansheeEngine;
  4. namespace BansheeEditor
  5. {
  6. /// <summary>
  7. /// Displays in-game viewport in the editor.
  8. /// </summary>
  9. public class GameWindow : EditorWindow
  10. {
  11. private const int HeaderHeight = 20;
  12. private static readonly Color BG_COLOR = Color.VeryDarkGray;
  13. private readonly AspectRatio[] aspectRatios =
  14. {
  15. new AspectRatio(16, 9),
  16. new AspectRatio(16, 10),
  17. new AspectRatio(5, 4),
  18. new AspectRatio(4, 3),
  19. new AspectRatio(3, 2)
  20. };
  21. private int selectedAspectRatio = 0;
  22. private GUIRenderTexture renderTextureGUI;
  23. private GUITexture renderTextureBg;
  24. private GUILabel noCameraLabel;
  25. /// <summary>
  26. /// Opens the game window.
  27. /// </summary>
  28. [MenuItem("Windows/Game", ButtonModifier.CtrlAlt, ButtonCode.G, 6000)]
  29. private static void OpenGameWindow()
  30. {
  31. OpenWindow<GameWindow>();
  32. }
  33. /// <summary>
  34. /// Starts execution of the game in the game window.
  35. /// </summary>
  36. [MenuItem("Tools/Play", 9300)]
  37. [ToolbarItem("Play", ToolbarIcon.Play, "Play", 1800, true)]
  38. private static void Play()
  39. {
  40. if (EditorApplication.IsPaused)
  41. EditorApplication.IsPaused = false;
  42. else
  43. EditorApplication.IsPlaying = !EditorApplication.IsPlaying;
  44. }
  45. /// <summary>
  46. /// Pauses the execution of the game on the current frame.
  47. /// </summary>
  48. [MenuItem("Tools/Pause", 9299)]
  49. [ToolbarItem("Pause", ToolbarIcon.Pause, "Pause", 1799)]
  50. private static void Pause()
  51. {
  52. EditorApplication.IsPaused = !EditorApplication.IsPaused;
  53. }
  54. /// <summary>
  55. /// Moves the execution of the game by one frame forward.
  56. /// </summary>
  57. [MenuItem("Tools/Step", 9298)]
  58. [ToolbarItem("Step", ToolbarIcon.Step, "Frame step", 1798)]
  59. private static void Step()
  60. {
  61. EditorApplication.FrameStep();
  62. }
  63. /// <inheritdoc/>
  64. protected override LocString GetDisplayName()
  65. {
  66. return new LocEdString("Game");
  67. }
  68. private void OnInitialize()
  69. {
  70. GUILayoutY mainLayout = GUI.AddLayoutY();
  71. string[] aspectRatioTitles = new string[aspectRatios.Length + 1];
  72. aspectRatioTitles[0] = "Free";
  73. for (int i = 0; i < aspectRatios.Length; i++)
  74. aspectRatioTitles[i + 1] = aspectRatios[i].width + ":" + aspectRatios[i].height;
  75. GUIListBoxField aspectField = new GUIListBoxField(aspectRatioTitles, new LocEdString("Aspect ratio"));
  76. aspectField.OnSelectionChanged += OnAspectRatioChanged;
  77. GUILayoutY buttonLayoutVert = mainLayout.AddLayoutY();
  78. GUILayoutX buttonLayout = buttonLayoutVert.AddLayoutX();
  79. buttonLayout.AddElement(aspectField);
  80. buttonLayout.AddFlexibleSpace();
  81. buttonLayoutVert.AddFlexibleSpace();
  82. renderTextureGUI = new GUIRenderTexture(null);
  83. renderTextureBg = new GUITexture(Builtin.WhiteTexture);
  84. renderTextureBg.SetTint(BG_COLOR);
  85. noCameraLabel = new GUILabel(new LocEdString("(No main camera in scene)"));
  86. GUIPanel rtPanel = mainLayout.AddPanel();
  87. rtPanel.AddElement(renderTextureGUI);
  88. GUIPanel bgPanel = rtPanel.AddPanel(1);
  89. bgPanel.AddElement(renderTextureBg);
  90. GUILayoutY alignLayoutY = rtPanel.AddLayoutY();
  91. alignLayoutY.AddFlexibleSpace();
  92. GUILayoutX alignLayoutX = alignLayoutY.AddLayoutX();
  93. alignLayoutX.AddFlexibleSpace();
  94. alignLayoutX.AddElement(noCameraLabel);
  95. alignLayoutX.AddFlexibleSpace();
  96. alignLayoutY.AddFlexibleSpace();
  97. UpdateRenderTexture(Width, Height);
  98. bool hasMainCamera = Scene.Camera != null;
  99. renderTextureGUI.Active = hasMainCamera;
  100. noCameraLabel.Active = !hasMainCamera;
  101. }
  102. private void OnEditorUpdate()
  103. {
  104. bool hasMainCamera = Scene.Camera != null;
  105. renderTextureGUI.Active = hasMainCamera;
  106. noCameraLabel.Active = !hasMainCamera;
  107. }
  108. private void OnDestroy()
  109. {
  110. EditorApplication.MainRenderTarget = null;
  111. }
  112. /// <summary>
  113. /// Creates or rebuilds the main render texture. Should be called at least once before using the
  114. /// game window. Should be called whenever the window is resized.
  115. /// </summary>
  116. /// <param name="width">Width of the scene render target, in pixels.</param>
  117. /// <param name="height">Height of the scene render target, in pixels.</param>
  118. private void UpdateRenderTexture(int width, int height)
  119. {
  120. height = height - HeaderHeight;
  121. int rtWidth = MathEx.Max(20, width);
  122. int rtHeight = MathEx.Max(20, height);
  123. if (selectedAspectRatio != 0) // 0 is free aspect
  124. {
  125. AspectRatio aspectRatio = aspectRatios[selectedAspectRatio - 1];
  126. int visibleAreaHeight = rtHeight;
  127. float aspectInv = aspectRatio.height/(float)aspectRatio.width;
  128. rtHeight = MathEx.RoundToInt(rtWidth*aspectInv);
  129. if (rtHeight > visibleAreaHeight)
  130. {
  131. rtHeight = visibleAreaHeight;
  132. float aspect = aspectRatio.width / (float)aspectRatio.height;
  133. rtWidth = MathEx.RoundToInt(rtHeight * aspect);
  134. }
  135. }
  136. RenderTexture2D renderTexture = new RenderTexture2D(PixelFormat.R8G8B8A8, rtWidth, rtHeight) {Priority = 1};
  137. EditorApplication.MainRenderTarget = renderTexture;
  138. renderTextureGUI.RenderTexture = renderTexture;
  139. int offsetX = (width - rtWidth)/2;
  140. int offsetY = (height - rtHeight)/2;
  141. Rect2I rtBounds = new Rect2I(offsetX, offsetY, rtWidth, rtHeight);
  142. renderTextureGUI.Bounds = rtBounds;
  143. Rect2I bgBounds = new Rect2I(0, 0, width, height);
  144. renderTextureBg.Bounds = bgBounds;
  145. }
  146. /// <summary>
  147. /// Triggered when the user selects a new aspect ratio from the drop down box.
  148. /// </summary>
  149. /// <param name="idx">Index of the aspect ratio the user selected.</param>
  150. private void OnAspectRatioChanged(int idx)
  151. {
  152. selectedAspectRatio = idx;
  153. UpdateRenderTexture(Width, Height);
  154. }
  155. /// <inheritdoc/>
  156. protected override void WindowResized(int width, int height)
  157. {
  158. UpdateRenderTexture(width, height);
  159. base.WindowResized(width, height);
  160. }
  161. /// <summary>
  162. /// Camera aspect ratio as numerator and denominator.
  163. /// </summary>
  164. struct AspectRatio
  165. {
  166. /// <summary>
  167. /// Creates a new object that holds the aspect ratio.
  168. /// </summary>
  169. /// <param name="width">Numerator of the aspect ratio.</param>
  170. /// <param name="height">Denominator of the aspect ratio.</param>
  171. public AspectRatio(int width, int height)
  172. {
  173. this.width = width;
  174. this.height = height;
  175. }
  176. public int width;
  177. public int height;
  178. }
  179. }
  180. }