Game1.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. #if ANDROID
  5. using Android.App;
  6. #endif
  7. using Microsoft.Xna.Framework;
  8. using Microsoft.Xna.Framework.Audio;
  9. using Microsoft.Xna.Framework.Content;
  10. using Microsoft.Xna.Framework.GamerServices;
  11. using Microsoft.Xna.Framework.Graphics;
  12. using Microsoft.Xna.Framework.Input;
  13. using Microsoft.Xna.Framework.Media;
  14. namespace RenderTarget2DSample
  15. {
  16. /// <summary>
  17. /// This is the main type for your game
  18. /// </summary>
  19. public class Game1 : Microsoft.Xna.Framework.Game
  20. {
  21. /// <summary>
  22. /// The GraphicsDeviceManager is what creates and automagically manages the game's GraphicsDevice.
  23. /// </summary>
  24. GraphicsDeviceManager graphics;
  25. /// <summary>
  26. /// We use SpriteBatch to draw all of our 2D graphics.
  27. /// </summary>
  28. SpriteBatch spriteBatch;
  29. /// <summary>
  30. /// This is the rendertarget we'll be drawing to.
  31. /// </summary>
  32. RenderTarget2D renderTarget;
  33. /// <summary>
  34. /// This is a texture we'll be using to load a picture of Seamus the dog.
  35. /// </summary>
  36. Texture2D mooTheMerciless;
  37. /// <summary>
  38. /// This is a texture we'll be using to load a picture of a tileable wood surface.
  39. /// </summary>
  40. Texture2D wood;
  41. bool oneTimeOnly = true;
  42. /// <summary>
  43. /// The constructor for our Game1 class.
  44. /// </summary>
  45. public Game1 ()
  46. {
  47. // Create the GraphicsDeviceManager for our game.
  48. graphics = new GraphicsDeviceManager (this);
  49. #if ANDROID || IPHONE
  50. graphics.IsFullScreen = true;
  51. #else
  52. graphics.PreferredBackBufferWidth = 800;
  53. graphics.PreferredBackBufferHeight = 600;
  54. graphics.IsFullScreen = false;
  55. #endif
  56. // Set the root directory of the game's ContentManager to the "Content" folder.
  57. Content.RootDirectory = "Content";
  58. }
  59. /// <summary>
  60. /// Allows the game to perform any initialization it needs to before starting to run.
  61. /// This is where it can query for any required services and load any non-graphic
  62. /// related content. Calling base.Initialize will enumerate through any components
  63. /// and initialize them as well.
  64. /// </summary>
  65. protected override void Initialize ()
  66. {
  67. // We don't have anything to initialize.
  68. base.Initialize ();
  69. }
  70. /// <summary>
  71. /// LoadContent will be called once per game and is the place to load
  72. /// all of your content.
  73. /// </summary>
  74. protected override void LoadContent ()
  75. {
  76. // Create a new SpriteBatch, which can be used to draw textures.
  77. spriteBatch = new SpriteBatch (GraphicsDevice);
  78. // Create a rendertarget that matches the back buffer's dimensions, does not generate mipmaps automatically
  79. // (the Reach profile requires power of 2 sizing in order to do that), uses an RGBA color format, and
  80. // has no depth buffer or stencil buffer.
  81. renderTarget = new RenderTarget2D (GraphicsDevice, GraphicsDevice.PresentationParameters.BackBufferWidth,
  82. GraphicsDevice.PresentationParameters.BackBufferHeight, false, SurfaceFormat.Color, DepthFormat.None);
  83. // Load in our wood tile.
  84. wood = Content.Load<Texture2D> ("wood");
  85. // Load in the picture of Seamus.
  86. mooTheMerciless = Content.Load<Texture2D> ("MooTheMerciless");
  87. }
  88. /// <summary>
  89. /// UnloadContent will be called once per game and is the place to unload
  90. /// all content.
  91. /// </summary>
  92. protected override void UnloadContent ()
  93. {
  94. // While not strictly necessary, you should always dispose of assets you create
  95. // (excluding those you load the the ContentManager) when those assets implement
  96. // IDisposable. RenderTarget2D is one such asset type, so we dispose of it properly.
  97. if (renderTarget != null) {
  98. // We put this in a try-catch block. The reason is that if for some odd reason this failed
  99. // (e.g. we were using threading and nulled out renderTarget on some other thread),
  100. // then none of the rest of the UnloadContent method would run. Here it doesn't make a
  101. // difference, but it's good practice nonethless.
  102. try {
  103. renderTarget.Dispose ();
  104. renderTarget = null;
  105. } catch {
  106. }
  107. }
  108. }
  109. /// <summary>
  110. /// Allows the game to run logic such as updating the world,
  111. /// checking for collisions, gathering input, and playing audio.
  112. /// </summary>
  113. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  114. protected override void Update (GameTime gameTime)
  115. {
  116. // Allows the game to exit. If this is a Windows version, I also like to check for an Esc key press. I put
  117. // it within an #if WINDOWS .. #endif block since that way it won't run on other platforms.
  118. if (GamePad.GetState (PlayerIndex.One).Buttons.Back == ButtonState.Pressed
  119. //#if WINDOWS
  120. || Keyboard.GetState ().IsKeyDown (Keys.Escape)
  121. //#endif
  122. ) {
  123. this.Exit ();
  124. }
  125. // We don't have any update logic since this is just an example usage of RenderTarget2D
  126. base.Update (gameTime);
  127. }
  128. /// <summary>
  129. /// This is called when the game should draw itself.
  130. /// </summary>
  131. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  132. protected override void Draw (GameTime gameTime)
  133. {
  134. // A one time only flag to help test for memory leaks
  135. if (oneTimeOnly)
  136. {
  137. oneTimeOnly = false;
  138. // Set renderTarget as the surface to draw to instead of the back buffer
  139. GraphicsDevice.SetRenderTarget (renderTarget);
  140. // Clear the renderTarget. By default it's all a bright purple color. I like to use Color.Transparent to
  141. // enable easy alpha blending.
  142. GraphicsDevice.Clear (Color.Transparent);
  143. Vector2 woodPosition = Vector2.Zero;
  144. // Begin drawing
  145. spriteBatch.Begin ();
  146. int xBlank = 0;
  147. int yBlank = 0;
  148. // Use nested do-whiles to fill the rendertarget with tiles. We use some trickery to draw every other tile
  149. do {
  150. do {
  151. // We use the modulus operator to get the remainder of dividing xBlank by 2. If xBlank is odd, it'll
  152. // return 1 and the spriteBatch.Draw call gets skipped. If it's even, it'll return 0 so
  153. // spriteBatch.Draw will get called and it'll draw a tile there.
  154. if (xBlank % 2 == 0) {
  155. spriteBatch.Draw (wood, woodPosition, Color.White);
  156. }
  157. // Increment xBlank by one so that every other tile will get drawn.
  158. xBlank++;
  159. // Increase the X coordinate of where we'll draw the wood tile in order to progressively draw
  160. // each column of tiles.
  161. woodPosition.X += wood.Width;
  162. // We draw so long as woodPosition.X is less than our renderTarget's width
  163. } while (woodPosition.X < renderTarget.Width);
  164. // We increment yBlank by one. Why is explained below.
  165. yBlank++;
  166. // We use the modulus operater to get the remainder of dividing yBlank by 2. If yBlank is odd, we reset
  167. // xBlank to 1. If it's even, we reset xBlank to 0. This way each row shifts by one so that the tiles
  168. // are drawn in a checkered pattern rather than in columns.
  169. if (yBlank % 2 == 0) {
  170. xBlank = 0;
  171. } else {
  172. xBlank = 1;
  173. }
  174. // Reset woodPosition.X to zero so that we start drawing from the beginning of the next row.
  175. woodPosition.X = 0;
  176. // Increase the Y coord of where we'll draw the wood tile in order to progressively draw each
  177. // row of tiles.
  178. woodPosition.Y += wood.Height;
  179. // We draw so long as woodPosition.Y is less than our renderTarget's width
  180. } while (woodPosition.Y < renderTarget.Height);
  181. // Now that we've drawn the wood tiles, we draw Moo the Merciless. We draw him centered in the rendertarget.
  182. spriteBatch.Draw (mooTheMerciless,
  183. new Vector2 ((renderTarget.Width / 2f) - (mooTheMerciless.Width / 2f), (renderTarget.Height / 2f) - (mooTheMerciless.Height / 2f)),
  184. Color.White);
  185. // End the spriteBatch draw.
  186. spriteBatch.End ();
  187. // Switch back to drawing onto the back buffer
  188. GraphicsDevice.SetRenderTarget (null);
  189. //GrabScreenshot(renderTarget);
  190. }
  191. // Now that we're back to drawing onto the back buffer, we want to clear it. If we had done so earlier
  192. // then when we switched to drawing to the render target, the old back buffer would've just be filled with
  193. // that bright purple color when we came back to it.
  194. GraphicsDevice.Clear (Color.CornflowerBlue);
  195. // Ok. At this point we have everything we drew in renderTarget, which we can use just like a regular Texture2D.
  196. // To make it look more interesting, we're going to scale up and down based on total elapsed time.
  197. float scale = 1.0f;
  198. if (gameTime.TotalGameTime.TotalSeconds % 10 < 5.0) {
  199. // We're running on a ten second scale timer. For the first five second we scale down from 1f to
  200. // no less than 0.01f.
  201. scale = MathHelper.Clamp (1f - (((float)gameTime.TotalGameTime.TotalSeconds % 5) / 5f), 0.01f, 1f);
  202. } else {
  203. // For the second five seconds, we scale up from no less than 0.01f up to 1f.
  204. scale = MathHelper.Clamp (((float)gameTime.TotalGameTime.TotalSeconds % 5) / 5f, 0.01f, 1f);
  205. }
  206. // Start spriteBatch again (this time drawing to the back buffer)
  207. spriteBatch.Begin ();
  208. // Now we draw our render target to the back buffer so that it will get displayed on the screen. We
  209. // position it in the center of the screen, but we make the origin be the center of the render target
  210. // such that it actually gets drawn centered (as opposed to shrinking and exanding with the left corner
  211. // in the center). We use our scale computation, and specify no SpriteEffects and an unused 0f for layer
  212. // depth
  213. spriteBatch.Draw (renderTarget,
  214. new Vector2 (GraphicsDevice.PresentationParameters.BackBufferWidth / 2, GraphicsDevice.PresentationParameters.BackBufferHeight / 2),
  215. null, Color.White, 0f, new Vector2 (renderTarget.Width / 2, renderTarget.Height / 2), scale,
  216. SpriteEffects.None, 0f);
  217. // End our spriteBatch call.
  218. spriteBatch.End ();
  219. base.Draw (gameTime);
  220. }
  221. public static void GrabScreenshot(RenderTarget2D rendertarget)
  222. {
  223. Color[] data = new Color[(rendertarget.Width * rendertarget.Height) * 3];
  224. //OpenTK.Graphics.ES11.GL.ReadPixels(0, 0, rendertarget.Width, rendertarget.Height, OpenTK.Graphics.ES11.All.Rgb, OpenTK.Graphics.ES11.All.UnsignedByte, ref data);
  225. rendertarget.GetData<Color>(data);
  226. }
  227. }
  228. }