GameWindow.cs 7.6 KB

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