SpriteEffects.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // SpriteEffects.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using Microsoft.Xna.Framework;
  12. using Microsoft.Xna.Framework.Content;
  13. using Microsoft.Xna.Framework.Graphics;
  14. using Microsoft.Xna.Framework.Input;
  15. #endregion
  16. namespace SpriteEffects
  17. {
  18. /// <summary>
  19. /// Sample demonstrating how shaders can be used to
  20. /// apply special effects to sprite rendering.
  21. /// </summary>
  22. public class SpriteEffectsGame : Microsoft.Xna.Framework.Game
  23. {
  24. #region Fields
  25. GraphicsDeviceManager graphics;
  26. KeyboardState lastKeyboardState = new KeyboardState ();
  27. GamePadState lastGamePadState = new GamePadState ();
  28. KeyboardState currentKeyboardState = new KeyboardState ();
  29. GamePadState currentGamePadState = new GamePadState ();
  30. // Enum describes all the rendering techniques used in this demo.
  31. enum DemoEffect
  32. {
  33. Desaturate,
  34. Disappear,
  35. RefractCat,
  36. RefractGlacier,
  37. Normalmap,
  38. }
  39. DemoEffect currentEffect = DemoEffect.RefractGlacier;
  40. // Effects used by this sample.
  41. Effect desaturateEffect;
  42. Effect disappearEffect;
  43. Effect normalmapEffect;
  44. Effect refractionEffect;
  45. // Textures used by this sample.
  46. Texture2D catTexture;
  47. Texture2D catNormalmapTexture;
  48. Texture2D glacierTexture;
  49. Texture2D waterfallTexture;
  50. // SpriteBatch instance used to render all the effects.
  51. SpriteBatch spriteBatch;
  52. #endregion
  53. #region Initialization
  54. public SpriteEffectsGame ()
  55. {
  56. graphics = new GraphicsDeviceManager (this);
  57. Content.RootDirectory = "Content";
  58. }
  59. /// <summary>
  60. /// Loads graphics content.
  61. /// </summary>
  62. protected override void LoadContent ()
  63. {
  64. //desaturateEffect = Content.Load<Effect> ("desaturate");
  65. //disappearEffect = Content.Load<Effect> ("disappear");
  66. //normalmapEffect = Content.Load<Effect> ("normalmap");
  67. //refractionEffect = Content.Load<Effect> ("refraction");
  68. desaturateEffect = new DesaturateEffect(GraphicsDevice);
  69. disappearEffect = new DisappearEffect(GraphicsDevice);
  70. normalmapEffect = new NormalmapEffect(GraphicsDevice);
  71. refractionEffect = new RefractionEffect(GraphicsDevice);
  72. catTexture = Content.Load<Texture2D> ("cat");
  73. catNormalmapTexture = Content.Load<Texture2D> ("cat_normalmap");
  74. glacierTexture = Content.Load<Texture2D> ("glacier");
  75. waterfallTexture = Content.Load<Texture2D> ("waterfall");
  76. spriteBatch = new SpriteBatch (graphics.GraphicsDevice);
  77. }
  78. #endregion
  79. #region Update and Draw
  80. /// <summary>
  81. /// Allows the game to run logic.
  82. /// </summary>
  83. protected override void Update (GameTime gameTime)
  84. {
  85. HandleInput ();
  86. if (NextButtonPressed ()) {
  87. currentEffect++;
  88. if (currentEffect > DemoEffect.Normalmap)
  89. currentEffect = 0;
  90. }
  91. base.Update (gameTime);
  92. }
  93. /// <summary>
  94. /// This is called when the game should draw itself.
  95. /// </summary>
  96. protected override void Draw (GameTime gameTime)
  97. {
  98. switch (currentEffect) {
  99. case DemoEffect.Desaturate:
  100. DrawDesaturate (gameTime);
  101. break;
  102. case DemoEffect.Disappear:
  103. DrawDisappear (gameTime);
  104. break;
  105. case DemoEffect.Normalmap:
  106. DrawNormalmap (gameTime);
  107. break;
  108. case DemoEffect.RefractCat:
  109. DrawRefractCat (gameTime);
  110. break;
  111. case DemoEffect.RefractGlacier:
  112. DrawRefractGlacier (gameTime);
  113. break;
  114. }
  115. base.Draw (gameTime);
  116. }
  117. /// <summary>
  118. /// Effect dynamically changes color saturation.
  119. /// </summary>
  120. void DrawDesaturate (GameTime gameTime)
  121. {
  122. GraphicsDevice.Clear(Color.White);
  123. // Begin the sprite batch, using our custom effect.
  124. spriteBatch.Begin (0, null, null, null, null, desaturateEffect);
  125. // Draw four copies of the same sprite with different saturation levels.
  126. // The saturation amount is passed into the effect using the alpha of the
  127. // SpriteBatch.Draw color parameter. This isn't as flexible as using a
  128. // regular effect parameter, but makes it easy to draw many sprites with
  129. // a different saturation amount for each. If we had used an effect
  130. // parameter for this, we would have to end the sprite batch, then begin
  131. // a new one, each time we wanted to change the saturation setting.
  132. byte pulsate = (byte)Pulsate (gameTime, 4, 0, 255);
  133. spriteBatch.Draw (glacierTexture,
  134. QuarterOfScreen (0, 0),
  135. new Color (255, 255, 255, 0));
  136. spriteBatch.Draw (glacierTexture,
  137. QuarterOfScreen (1, 0),
  138. new Color (255, 255, 255, 64));
  139. spriteBatch.Draw (glacierTexture,
  140. QuarterOfScreen (0, 1),
  141. new Color (255, 255, 255, 255));
  142. spriteBatch.Draw (glacierTexture,
  143. QuarterOfScreen (1, 1),
  144. new Color (255, 255, 255, pulsate));
  145. // End the sprite batch.
  146. spriteBatch.End ();
  147. }
  148. /// <summary>
  149. /// Effect uses a scrolling overlay texture to make different parts of
  150. /// an image fade in or out at different speeds.
  151. /// </summary>
  152. void DrawDisappear (GameTime gameTime)
  153. {
  154. //GraphicsDevice.Clear(Color.White);
  155. // Draw the background image.
  156. spriteBatch.Begin ();
  157. spriteBatch.Draw (glacierTexture, GraphicsDevice.Viewport.Bounds, Color.White);
  158. spriteBatch.End ();
  159. // Set an effect parameter to make our overlay
  160. // texture scroll in a giant circle.
  161. //TextureSampler
  162. disappearEffect.Parameters ["OverlayScroll"].SetValue (
  163. MoveInCircle (gameTime, 0.8f) * 0.25f);
  164. // Set the overlay texture (as texture 1,
  165. // because 0 will be the main sprite texture).
  166. graphics.GraphicsDevice.Textures [1] = waterfallTexture;
  167. // Begin the sprite batch.
  168. spriteBatch.Begin (0, null, null, null, null, disappearEffect);
  169. // Draw the sprite, passing the fade amount as the
  170. // alpha of the SpriteBatch.Draw color parameter.
  171. byte fade = (byte)Pulsate (gameTime, 2, 0, 255);
  172. spriteBatch.Draw (catTexture,
  173. MoveInCircle (gameTime, catTexture, 1),
  174. new Color (255, 255, 255, fade));
  175. // End the sprite batch.
  176. spriteBatch.End ();
  177. }
  178. /// <summary>
  179. // Effect uses a scrolling displacement texture to offset the position of
  180. // the main texture.
  181. /// </summary>
  182. void DrawRefractCat (GameTime gameTime)
  183. {
  184. // Draw the background image.
  185. spriteBatch.Begin ();
  186. spriteBatch.Draw (glacierTexture, GraphicsDevice.Viewport.Bounds, Color.White);
  187. spriteBatch.End ();
  188. // Set an effect parameter to make the
  189. // displacement texture scroll in a giant circle.
  190. refractionEffect.Parameters ["DisplacementScroll"].SetValue (
  191. MoveInCircle (gameTime, 0.1f));
  192. // Set the displacement texture.
  193. graphics.GraphicsDevice.Textures [1] = waterfallTexture;
  194. // Begin the sprite batch.
  195. spriteBatch.Begin (0, null, null, null, null, refractionEffect);
  196. // Draw the sprite.
  197. spriteBatch.Draw (catTexture,
  198. MoveInCircle (gameTime, catTexture, 1),
  199. Color.White);
  200. // End the sprite batch.
  201. spriteBatch.End ();
  202. }
  203. /// <summary>
  204. // Effect uses a scrolling displacement texture to offset the position of
  205. // the main texture.
  206. /// </summary>
  207. void DrawRefractGlacier (GameTime gameTime)
  208. {
  209. // Set an effect parameter to make the
  210. // displacement texture scroll in a giant circle.
  211. refractionEffect.Parameters ["DisplacementScroll"].SetValue (
  212. MoveInCircle (gameTime, 0.2f));
  213. // Set the displacement texture.
  214. graphics.GraphicsDevice.Textures [1] = glacierTexture;
  215. // Begin the sprite batch.
  216. spriteBatch.Begin (0, null, null, null, null, refractionEffect);
  217. //spriteBatch.Begin();
  218. // Because the effect will displace the texture coordinates before
  219. // sampling the main texture, the coordinates could sometimes go right
  220. // off the edges of the texture, which looks ugly. To prevent this, we
  221. // adjust our sprite source region to leave a little border around the
  222. // edge of the texture. The displacement effect will then just move the
  223. // texture coordinates into this border region, without ever hitting
  224. // the edge of the texture.
  225. Rectangle croppedGlacier = new Rectangle (32, 32,
  226. glacierTexture.Width - 64,
  227. glacierTexture.Height - 64);
  228. spriteBatch.Draw (glacierTexture,
  229. GraphicsDevice.Viewport.Bounds,
  230. //croppedGlacier,
  231. Color.White);
  232. // End the sprite batch.
  233. spriteBatch.End ();
  234. }
  235. /// <summary>
  236. /// Effect uses a normalmap texture to apply realtime lighting while
  237. /// drawing a 2D sprite.
  238. /// </summary>
  239. void DrawNormalmap (GameTime gameTime)
  240. {
  241. // Draw the background image.
  242. spriteBatch.Begin ();
  243. spriteBatch.Draw (glacierTexture, GraphicsDevice.Viewport.Bounds, Color.White);
  244. spriteBatch.End ();
  245. // Animate the light direction.
  246. Vector2 spinningLight = MoveInCircle (gameTime, 1.5f);
  247. double time = gameTime.TotalGameTime.TotalSeconds;
  248. float tiltUpAndDown = 0.5f + (float)Math.Cos (time * 0.75) * 0.1f;
  249. Vector3 lightDirection = new Vector3 (spinningLight * tiltUpAndDown,
  250. 1 - tiltUpAndDown);
  251. lightDirection.Normalize ();
  252. normalmapEffect.Parameters ["LightDirection"].SetValue (lightDirection);
  253. // Set the normalmap texture.
  254. graphics.GraphicsDevice.Textures [1] = catNormalmapTexture;
  255. // Begin the sprite batch.
  256. spriteBatch.Begin (0, null, null, null, null, normalmapEffect);
  257. // Draw the sprite.
  258. spriteBatch.Draw (catTexture, CenterOnScreen (catTexture), Color.Azure);
  259. // End the sprite batch.
  260. spriteBatch.End ();
  261. // End the sprite batch.
  262. spriteBatch.End ();
  263. }
  264. /// <summary>
  265. /// Helper calculates the destination rectangle needed
  266. /// to draw a sprite to one quarter of the screen.
  267. /// </summary>
  268. Rectangle QuarterOfScreen (int x, int y)
  269. {
  270. Viewport viewport = graphics.GraphicsDevice.Viewport;
  271. int w = viewport.Width / 2;
  272. int h = viewport.Height / 2;
  273. return new Rectangle (w * x, h * y, w, h);
  274. }
  275. /// <summary>
  276. /// Helper calculates the destination position needed
  277. /// to center a sprite in the middle of the screen.
  278. /// </summary>
  279. Vector2 CenterOnScreen (Texture2D texture)
  280. {
  281. Viewport viewport = graphics.GraphicsDevice.Viewport;
  282. int x = (viewport.Width - texture.Width) / 2;
  283. int y = (viewport.Height - texture.Height) / 2;
  284. return new Vector2 (x, y);
  285. }
  286. /// <summary>
  287. /// Helper computes a value that oscillates over time.
  288. /// </summary>
  289. static float Pulsate (GameTime gameTime, float speed, float min, float max)
  290. {
  291. double time = gameTime.TotalGameTime.TotalSeconds * speed;
  292. return min + ((float)Math.Sin (time) + 1) / 2 * (max - min);
  293. }
  294. /// <summary>
  295. /// Helper for moving a value around in a circle.
  296. /// </summary>
  297. static Vector2 MoveInCircle (GameTime gameTime, float speed)
  298. {
  299. double time = gameTime.TotalGameTime.TotalSeconds * speed;
  300. float x = (float)Math.Cos (time);
  301. float y = (float)Math.Sin (time);
  302. return new Vector2 (x, y);
  303. }
  304. /// <summary>
  305. /// Helper for moving a sprite around in a circle.
  306. /// </summary>
  307. Vector2 MoveInCircle (GameTime gameTime, Texture2D texture, float speed)
  308. {
  309. Viewport viewport = graphics.GraphicsDevice.Viewport;
  310. float x = (viewport.Width - texture.Width) / 2;
  311. float y = (viewport.Height - texture.Height) / 2;
  312. return MoveInCircle (gameTime, speed) * 128 + new Vector2 (x, y);
  313. }
  314. #endregion
  315. #region Handle Input
  316. /// <summary>
  317. /// Handles input for quitting the game.
  318. /// </summary>
  319. private void HandleInput ()
  320. {
  321. lastKeyboardState = currentKeyboardState;
  322. lastGamePadState = currentGamePadState;
  323. currentKeyboardState = Keyboard.GetState ();
  324. currentGamePadState = GamePad.GetState (PlayerIndex.One);
  325. // Check for exit.
  326. if (currentKeyboardState.IsKeyDown (Keys.Escape) ||
  327. currentGamePadState.Buttons.Back == ButtonState.Pressed) {
  328. Exit ();
  329. }
  330. }
  331. /// <summary>
  332. /// Checks whether the user wants to advance to the next rendering effect.
  333. /// </summary>
  334. bool NextButtonPressed ()
  335. {
  336. // Have they pressed the space bar?
  337. if (currentKeyboardState.IsKeyDown (Keys.Space) &&
  338. !lastKeyboardState.IsKeyDown (Keys.Space))
  339. return true;
  340. // Have they pressed the gamepad A button?
  341. if (currentGamePadState.Buttons.A == ButtonState.Pressed &&
  342. lastGamePadState.Buttons.A == ButtonState.Released)
  343. return true;
  344. return false;
  345. }
  346. #endregion
  347. }
  348. }