GameWindow.cs 6.5 KB

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