RenderToTexture.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. //-----------------------------------------------------------------------------
  2. // RenderToTexture.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using Microsoft.Xna.Framework.Graphics;
  8. using System;
  9. using System.Collections;
  10. using System.Text;
  11. using RacingGame.Graphics;
  12. using RacingGame.Helpers;
  13. using Texture = RacingGame.Graphics.Texture;
  14. using Model = RacingGame.Graphics.Model;
  15. using XnaTexture = Microsoft.Xna.Framework.Graphics.Texture2D;
  16. using Microsoft.Xna.Framework;
  17. using RacingGame.GameLogic;
  18. using Microsoft.Xna.Framework.Input;
  19. namespace RacingGame.Shaders
  20. {
  21. /// <summary>
  22. /// Render to texture helper class based on the Texture class.
  23. /// This class allows to render stuff onto textures, if thats not
  24. /// supported, it will just not work and report an engine log message.
  25. /// This class is required for most PostScreenShaders.
  26. /// </summary>
  27. public class RenderToTexture : Texture
  28. {
  29. /// <summary>
  30. /// Our render target we are going to render to. Much easier than in MDX
  31. /// where you have to use Surfaces, etc. Also supports the Xbox360 model
  32. /// of resolving the render target texture before we can use it, otherwise
  33. /// the RenderToTexture class would not work on the Xbox360.
  34. /// </summary>
  35. RenderTarget2D renderTarget = null;
  36. /*
  37. /// <summary>
  38. /// Z buffer surface for shadow mapping render targets that do not
  39. /// fit in our resolution. Usually unused!
  40. /// </summary>
  41. DepthStencilBuffer zBufferSurface = null;
  42. /// <summary>
  43. /// ZBuffer surface
  44. /// </summary>
  45. /// <returns>Surface</returns>
  46. public DepthStencilBuffer ZBufferSurface
  47. {
  48. get
  49. {
  50. return zBufferSurface;
  51. }
  52. }
  53. */
  54. /// <summary>
  55. /// Posible size types for creating a RenderToTexture object.
  56. /// </summary>
  57. public enum SizeType
  58. {
  59. /// <summary>
  60. /// Uses the full screen size for this texture
  61. /// </summary>
  62. FullScreen,
  63. /// <summary>
  64. /// Uses half the full screen size, e.g. 800x600 becomes 400x300
  65. /// </summary>
  66. HalfScreen,
  67. /// <summary>
  68. /// Uses a quarter of the full screen size, e.g. 800x600 becomes 200x150
  69. /// </summary>
  70. QuarterScreen,
  71. /// <summary>
  72. /// Shadow map texture, usually 1024x1024, but can also be better
  73. /// like 2048x2048 or 4096x4096.
  74. /// </summary>
  75. ShadowMap,
  76. }
  77. /// <summary>
  78. /// Size type
  79. /// </summary>
  80. private SizeType sizeType;
  81. /// <summary>
  82. /// Calc size
  83. /// </summary>
  84. private void CalcSize()
  85. {
  86. switch (sizeType)
  87. {
  88. case SizeType.FullScreen:
  89. texWidth = BaseGame.Width;
  90. texHeight = BaseGame.Height;
  91. break;
  92. case SizeType.HalfScreen:
  93. texWidth = BaseGame.Width / 2;
  94. texHeight = BaseGame.Height / 2;
  95. break;
  96. case SizeType.QuarterScreen:
  97. texWidth = BaseGame.Width / 4;
  98. texHeight = BaseGame.Height / 4;
  99. break;
  100. case SizeType.ShadowMap:
  101. // Use a larger texture for high detail
  102. if (BaseGame.HighDetail)
  103. {
  104. texWidth = 2048;
  105. texHeight = 2048;
  106. }
  107. else
  108. {
  109. texWidth = 1024;
  110. texHeight = 1024;
  111. }
  112. break;
  113. }
  114. CalcHalfPixelSize();
  115. }
  116. /// <summary>
  117. /// Does this texture use some high percision format? Better than 8 bit color?
  118. /// </summary>
  119. private bool usesHighPercisionFormat = false;
  120. /// <summary>
  121. /// Render target
  122. /// </summary>
  123. /// <returns>Render target 2D</returns>
  124. public RenderTarget2D RenderTarget
  125. {
  126. get
  127. {
  128. return renderTarget;
  129. }
  130. }
  131. /// <summary>
  132. /// Override how to get XnaTexture, we have to resolve the render target
  133. /// for supporting the Xbox, which requires calling Resolve first!
  134. /// After that you can call this property to get the current texture.
  135. /// </summary>
  136. /// <returns>XnaTexture</returns>
  137. public override XnaTexture XnaTexture
  138. {
  139. get
  140. {
  141. if (alreadyResolved)
  142. internalXnaTexture = renderTarget;
  143. return internalXnaTexture;
  144. }
  145. }
  146. /// <summary>
  147. /// Does this texture use some high percision format? Better than 8 bit color?
  148. /// </summary>
  149. public bool UsesHighPercisionFormat
  150. {
  151. get
  152. {
  153. return usesHighPercisionFormat;
  154. }
  155. }
  156. /// <summary>
  157. /// Id for each created RenderToTexture for the generated filename.
  158. /// </summary>
  159. private static int RenderToTextureGlobalInstanceId = 0;
  160. /// <summary>
  161. /// Creates an offscreen texture with the specified size which
  162. /// can be used for render to texture.
  163. /// </summary>
  164. public RenderToTexture(SizeType setSizeType)
  165. {
  166. sizeType = setSizeType;
  167. CalcSize();
  168. texFilename = "RenderToTexture instance " +
  169. RenderToTextureGlobalInstanceId++;
  170. Create();
  171. BaseGame.AddRemRenderToTexture(this);
  172. }
  173. /// <summary>
  174. /// Handle the DeviceReset event, we have to re-create all our render targets.
  175. /// </summary>
  176. public void HandleDeviceReset()
  177. {
  178. // Respond to resolution changes
  179. CalcSize();
  180. // Clear resolved texture
  181. alreadyResolved = false;
  182. internalXnaTexture = null;
  183. // Re-create
  184. Create();
  185. }
  186. /// <summary>
  187. /// Create
  188. /// </summary>
  189. private void Create()
  190. {
  191. SurfaceFormat outSF;
  192. DepthFormat outDF;
  193. int outMSC;
  194. int MultisampleCount = 2;
  195. if (BaseGame.Device.PresentationParameters.BackBufferHeight == 720)
  196. {
  197. MultisampleCount = 4;
  198. }
  199. // UWP COMMENT OUT
  200. //if (sizeType == SizeType.ShadowMap ||
  201. // BaseGame.CurrentPlatform == PlatformID.Win32NT)
  202. //{
  203. // MultisampleCount = 0;
  204. //}
  205. // Rgba64 is a HiDef-only format and is not available on Android or iOS.
  206. // Android also does not reliably support MSAA on render targets.
  207. outSF = OperatingSystem.IsAndroid() || OperatingSystem.IsIOS() ? SurfaceFormat.Color : SurfaceFormat.Rgba64;
  208. outDF = BaseGame.BackBufferDepthFormat;
  209. outMSC = OperatingSystem.IsAndroid() || OperatingSystem.IsIOS() ? 0 : MultisampleCount;
  210. if (sizeType == SizeType.ShadowMap)
  211. outMSC = 0;
  212. // Create render target of specified size.
  213. renderTarget = new RenderTarget2D (
  214. BaseGame.Device,
  215. texWidth, texHeight, false,
  216. outSF, outDF, outMSC, RenderTargetUsage.DiscardContents);
  217. if (outSF != SurfaceFormat.Color)
  218. usesHighPercisionFormat = true;
  219. loaded = true;
  220. }
  221. /// <summary>
  222. /// Clear render target (call SetRenderTarget first)
  223. /// </summary>
  224. public void Clear(Color clearColor)
  225. {
  226. if (loaded == false ||
  227. renderTarget == null)
  228. return;
  229. BaseGame.Device.Clear(
  230. ClearOptions.Target | ClearOptions.DepthBuffer,
  231. clearColor, 1.0f, 0);
  232. }
  233. /// <summary>
  234. /// Set render target to this texture to render stuff on it.
  235. /// </summary>
  236. public bool SetRenderTarget()
  237. {
  238. if (loaded == false ||
  239. renderTarget == null)
  240. return false;
  241. BaseGame.SetRenderTarget(renderTarget, false);
  242. return true;
  243. }
  244. /// <summary>
  245. /// Make sure we don't call XnaTexture before resolving for the first time!
  246. /// </summary>
  247. bool alreadyResolved = false;
  248. /// <summary>
  249. /// Resolve render target. For windows developers this method may seem
  250. /// strange, why not just use the rendertarget's texture? Well, this is
  251. /// just for the Xbox360 support. The Xbox requires that you call Resolve
  252. /// first before using the rendertarget texture. The reason for that is
  253. /// copying the data over from the EPRAM to the video memory, for more
  254. /// details read the XNA docs.
  255. /// Note: This method will only work if the render target was set before
  256. /// with SetRenderTarget, else an exception will be thrown to ensure
  257. /// correct calling order.
  258. /// </summary>
  259. public void Resolve()
  260. {
  261. // Make sure this render target is currently set!
  262. if (BaseGame.CurrentRenderTarget != renderTarget)
  263. throw new InvalidOperationException(
  264. "You can't call Resolve without first setting the render target!");
  265. alreadyResolved = true;
  266. // fix
  267. //BaseGame.Device.ResolveRenderTarget(0);
  268. BaseGame.Device.SetRenderTarget(null);
  269. }
  270. }
  271. }