BaseGame.cs 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573
  1. //-----------------------------------------------------------------------------
  2. // BaseGame.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using Microsoft.Xna.Framework;
  8. using Microsoft.Xna.Framework.Audio;
  9. using Microsoft.Xna.Framework.Content;
  10. using Microsoft.Xna.Framework.Graphics;
  11. using Microsoft.Xna.Framework.Input;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Threading;
  15. using RacingGame.GameLogic;
  16. using RacingGame.Helpers;
  17. using RacingGame.Properties;
  18. using RacingGame.Shaders;
  19. using RacingGame.Sounds;
  20. #if GAMERSERVICES
  21. using Microsoft.Xna.Framework.GamerServices;
  22. #endif
  23. using RacingGame.GameScreens;
  24. namespace RacingGame.Graphics
  25. {
  26. /// <summary>
  27. /// Base game class for all the basic game support.
  28. /// Connects all our helper classes together and makes our life easier!
  29. /// Note: This game was designed for 16:9 (e.g. 1920x1200), but it
  30. /// also works just fine for 4:3 (1024x768, 800x600, etc.).
  31. /// This is the reason you might see 1024x640 instead of 1024x768 in
  32. /// some width/height calculations and the UI textures.
  33. /// The game looks best at 1920x1080 (HDTV 1080p resolution).
  34. /// </summary>
  35. public partial class BaseGame : Microsoft.Xna.Framework.Game
  36. {
  37. /// <summary>
  38. /// Background color
  39. /// </summary>
  40. private static readonly Color BackgroundColor = Color.Black;
  41. /// <summary>
  42. /// Field of view and near and far plane distances for the
  43. /// ProjectionMatrix creation.
  44. /// </summary>
  45. private const float FieldOfView = (float)Math.PI / 2,
  46. NearPlane = 0.5f,
  47. FarPlane = 1750;
  48. /// <summary>
  49. /// Viewable field of view for object visibility testing (see Model class)
  50. /// </summary>
  51. public const float ViewableFieldOfView = FieldOfView / 1.125f;
  52. // UWP COMMENT OUT
  53. // public static PlatformID CurrentPlatform = Environment.OSVersion.Platform;
  54. /// <summary>
  55. /// Graphics device manager, used for the graphics creation and holds
  56. /// the GraphicsDevice.
  57. /// </summary>
  58. public static GraphicsDeviceManager graphicsManager = null;
  59. /// <summary>
  60. /// Content manager
  61. /// </summary>
  62. protected static ContentManager content = null;
  63. /// <summary>
  64. /// UI Renderer helper class for all 2d rendering.
  65. /// </summary>
  66. protected static UIRenderer ui = null;
  67. /// <summary>
  68. /// Our screen resolution: Width and height of visible render area.
  69. /// </summary>
  70. protected static int width, height;
  71. /// <summary>
  72. /// Aspect ratio of our current resolution
  73. /// </summary>
  74. private static float aspectRatio = 1.0f;
  75. /// <summary>
  76. /// Remember windows title to check if we are in certain unit tests!
  77. /// </summary>
  78. private static string remWindowsTitle = "";
  79. /// <summary>
  80. /// Get windows title to check if we are in certain unit tests!
  81. /// </summary>
  82. public static string WindowsTitle
  83. {
  84. get
  85. {
  86. return remWindowsTitle;
  87. }
  88. }
  89. /// <summary>
  90. /// Line manager 2D
  91. /// </summary>
  92. private static LineManager2D lineManager2D = null;
  93. /// <summary>
  94. /// Line manager 3D
  95. /// </summary>
  96. private static LineManager3D lineManager3D = null;
  97. /// <summary>
  98. /// Mesh render manager to render meshes of models in a highly
  99. /// optimized manner. We don't really have anything stored in here
  100. /// except for a sorted list on how to render everything based on the
  101. /// techniques and the materials and links to the renderable meshes.
  102. /// </summary>
  103. private static MeshRenderManager meshRenderManager =
  104. new MeshRenderManager();
  105. /// <summary>
  106. /// Matrices for shaders. Used in a similar way than in Rocket Commander,
  107. /// but since we don't have a fixed function pipeline here we just use
  108. /// these values in the shader. Make sure to set all matrices before
  109. /// calling a shader. Inside a shader you have to update the shader
  110. /// parameter too, just setting the WorldMatrix alone does not work.
  111. /// </summary>
  112. private static Matrix worldMatrix,
  113. viewMatrix,
  114. projectionMatrix;
  115. /// <summary>
  116. /// Light direction, please read matrices info above for more details.
  117. /// The same things apply here.
  118. /// </summary>
  119. private static Vector3 lightDirection = new Vector3(0, 0, 1);
  120. /// <summary>
  121. /// Light direction
  122. /// </summary>
  123. /// <returns>Vector 3</returns>
  124. public static Vector3 LightDirection
  125. {
  126. get
  127. {
  128. return lightDirection;
  129. }
  130. set
  131. {
  132. lightDirection = value;
  133. lightDirection.Normalize();
  134. }
  135. }
  136. /// <summary>
  137. /// Elapsed time this frame in ms. Always have something valid here
  138. /// in case we devide through this values!
  139. /// </summary>
  140. private static float elapsedTimeThisFrameInMs = 0.001f, totalTimeMs = 0,
  141. lastFrameTotalTimeMs = 0;
  142. /// <summary>
  143. /// Helper for calculating frames per second.
  144. /// </summary>
  145. private static float startTimeThisSecond = 0;
  146. /// <summary>
  147. /// For more accurate frames per second calculations,
  148. /// just count for one second, then fpsLastSecond is updated.
  149. /// Btw: Start with 1 to help some tests avoid the devide through zero
  150. /// problem.
  151. /// </summary>
  152. private static int
  153. frameCountThisSecond = 0,
  154. totalFrameCount = 0,
  155. fpsLastSecond = 60;
  156. /// <summary>
  157. /// Return true every checkMilliseconds.
  158. /// </summary>
  159. /// <param name="checkMilliseconds">Check ms</param>
  160. /// <returns>Bool</returns>
  161. public static bool EveryMillisecond(int checkMilliseconds)
  162. {
  163. return (int)(lastFrameTotalTimeMs / checkMilliseconds) !=
  164. (int)(totalTimeMs / checkMilliseconds);
  165. }
  166. #if GAMERSERVICES
  167. private static GamerServicesComponent gamerServicesComponent = null;
  168. public static GamerServicesComponent GamerServicesComponent
  169. {
  170. get { return gamerServicesComponent; }
  171. }
  172. #endif
  173. static public GraphicsDevice Device
  174. {
  175. get
  176. {
  177. return graphicsManager.GraphicsDevice;
  178. }
  179. }
  180. /// <summary>
  181. /// Back buffer depth format
  182. /// </summary>
  183. static DepthFormat backBufferDepthFormat = DepthFormat.Depth24;
  184. /// <summary>
  185. /// Back buffer depth format
  186. /// </summary>
  187. /// <returns>Surface format</returns>
  188. public static DepthFormat BackBufferDepthFormat
  189. {
  190. get
  191. {
  192. return backBufferDepthFormat;
  193. }
  194. }
  195. private static bool alreadyCheckedGraphicsOptions = false;
  196. /// <summary>
  197. /// Check options and PS version
  198. /// </summary>
  199. internal static void CheckOptionsAndPSVersion()
  200. {
  201. GraphicsDevice device = Device;
  202. if (device == null)
  203. throw new InvalidOperationException("Device is not created yet!");
  204. alreadyCheckedGraphicsOptions = true;
  205. usePostScreenShaders = GameSettings.Default.PostScreenEffects;
  206. //TODO Fix Shadow Maps!
  207. allowShadowMapping = GameSettings.Default.ShadowMapping;
  208. highDetail = GameSettings.Default.HighDetail;
  209. }
  210. /// <summary>
  211. /// Fullscreen
  212. /// </summary>
  213. /// <returns>Bool</returns>
  214. public static bool Fullscreen
  215. {
  216. get
  217. {
  218. return graphicsManager.IsFullScreen;
  219. }
  220. }
  221. private static bool highDetail = true;
  222. /// <summary>
  223. /// High detail
  224. /// </summary>
  225. /// <returns>Bool</returns>
  226. public static bool HighDetail
  227. {
  228. get
  229. {
  230. if (alreadyCheckedGraphicsOptions == false)
  231. CheckOptionsAndPSVersion();
  232. return highDetail;
  233. }
  234. }
  235. private static bool allowShadowMapping = true;
  236. /// <summary>
  237. /// Allow shadow mapping
  238. /// </summary>
  239. /// <returns>Bool</returns>
  240. public static bool AllowShadowMapping
  241. {
  242. get
  243. {
  244. if (alreadyCheckedGraphicsOptions == false)
  245. CheckOptionsAndPSVersion();
  246. return allowShadowMapping;
  247. }
  248. }
  249. private static bool usePostScreenShaders = false;
  250. /// <summary>
  251. /// Use post screen shaders
  252. /// </summary>
  253. /// <returns>Bool</returns>
  254. public static bool UsePostScreenShaders
  255. {
  256. get
  257. {
  258. //if (alreadyCheckedGraphicsOptions == false)
  259. // CheckOptionsAndPSVersion();
  260. return usePostScreenShaders;
  261. }
  262. }
  263. private static bool mustApplyDeviceChanges = false;
  264. internal static void ApplyResolutionChange()
  265. {
  266. int resolutionWidth = GameSettings.Default == null ? 0 :
  267. GameSettings.Default.ResolutionWidth;
  268. int resolutionHeight = GameSettings.Default == null ? 0 :
  269. GameSettings.Default.ResolutionHeight;
  270. // Use current desktop resolution if autodetect is selected.
  271. if (resolutionWidth <= 0 ||
  272. resolutionHeight <= 0)
  273. {
  274. resolutionWidth =
  275. GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
  276. resolutionHeight =
  277. GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
  278. }
  279. #if XBOX360 || XBOXONE
  280. // Xbox 360 graphics settings are fixed
  281. graphicsManager.IsFullScreen = true;
  282. graphicsManager.PreferredBackBufferWidth =
  283. GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
  284. graphicsManager.PreferredBackBufferHeight =
  285. GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
  286. #else
  287. graphicsManager.PreferredBackBufferWidth = resolutionWidth;
  288. graphicsManager.PreferredBackBufferHeight = resolutionHeight;
  289. graphicsManager.IsFullScreen = false;//GameSettings.Default.Fullscreen;
  290. graphicsManager.GraphicsDevice.Viewport = new Viewport (0, 0, resolutionWidth, resolutionHeight);
  291. mustApplyDeviceChanges = true;
  292. #endif
  293. }
  294. /// <summary>
  295. /// Content
  296. /// </summary>
  297. /// <returns>Content manager</returns>
  298. public new static ContentManager Content
  299. {
  300. get
  301. {
  302. return content;
  303. }
  304. }
  305. /// <summary>
  306. /// User interface renderer helper ^^
  307. /// </summary>
  308. /// <returns>UIRenderer</returns>
  309. public static UIRenderer UI
  310. {
  311. get
  312. {
  313. return ui;
  314. }
  315. }
  316. /// <summary>
  317. /// Mesh render manager to render meshes of models in a highly
  318. /// optimized manner.
  319. /// </summary>
  320. /// <returns>Mesh render manager</returns>
  321. public static MeshRenderManager MeshRenderManager
  322. {
  323. get
  324. {
  325. return meshRenderManager;
  326. }
  327. }
  328. /// <summary>
  329. /// Width
  330. /// </summary>
  331. /// <returns>Int</returns>
  332. public static int Width
  333. {
  334. get
  335. {
  336. return width;
  337. }
  338. }
  339. /// <summary>
  340. /// Height
  341. /// </summary>
  342. /// <returns>Int</returns>
  343. public static int Height
  344. {
  345. get
  346. {
  347. return height;
  348. }
  349. }
  350. /// <summary>
  351. /// Aspect ratio
  352. /// </summary>
  353. /// <returns>Float</returns>
  354. public static float AspectRatio
  355. {
  356. get
  357. {
  358. return aspectRatio;
  359. }
  360. }
  361. /// <summary>
  362. /// Resolution rectangle
  363. /// </summary>
  364. /// <returns>Rectangle</returns>
  365. public static Rectangle ResolutionRect
  366. {
  367. get
  368. {
  369. return new Rectangle(0, 0, width, height);
  370. }
  371. }
  372. /// <summary>
  373. /// XToRes helper method to convert 1024x640 to the current
  374. /// screen resolution. Used to position UI elements.
  375. /// </summary>
  376. /// <param name="xIn1024px">X in 1024px width resolution</param>
  377. /// <returns>Int</returns>
  378. public static int XToRes(int xIn1024px)
  379. {
  380. return (int)Math.Round(xIn1024px * BaseGame.Width / 1024.0f);
  381. }
  382. /// <summary>
  383. /// YToRes helper method to convert 1024x640 to the current
  384. /// screen resolution. Used to position UI elements.
  385. /// </summary>
  386. /// <param name="yIn640px">Y in 640px height</param>
  387. /// <returns>Int</returns>
  388. public static int YToRes(int yIn640px)
  389. {
  390. return (int)Math.Round(yIn640px * BaseGame.Height / 640.0f);
  391. }
  392. /// <summary>
  393. /// YTo res 768
  394. /// </summary>
  395. /// <param name="yIn768px">Y in 768px</param>
  396. /// <returns>Int</returns>
  397. public static int YToRes768(int yIn768px)
  398. {
  399. return (int)Math.Round(yIn768px * BaseGame.Height / 768.0f);
  400. }
  401. /// <summary>
  402. /// XTo res 1600
  403. /// </summary>
  404. /// <param name="xIn1600px">X in 1600px</param>
  405. /// <returns>Int</returns>
  406. public static int XToRes1600(int xIn1600px)
  407. {
  408. return (int)Math.Round(xIn1600px * BaseGame.Width / 1600.0f);
  409. }
  410. /// <summary>
  411. /// YTo res 1200
  412. /// </summary>
  413. /// <param name="yIn768px">Y in 1200px</param>
  414. /// <returns>Int</returns>
  415. public static int YToRes1200(int yIn1200px)
  416. {
  417. return (int)Math.Round(yIn1200px * BaseGame.Height / 1200.0f);
  418. }
  419. /// <summary>
  420. /// XTo res 1400
  421. /// </summary>
  422. /// <param name="xIn1400px">X in 1400px</param>
  423. /// <returns>Int</returns>
  424. public static int XToRes1400(int xIn1400px)
  425. {
  426. return (int)Math.Round(xIn1400px * BaseGame.Width / 1400.0f);
  427. }
  428. /// <summary>
  429. /// YTo res 1200
  430. /// </summary>
  431. /// <param name="yIn1050px">Y in 1050px</param>
  432. /// <returns>Int</returns>
  433. public static int YToRes1050(int yIn1050px)
  434. {
  435. return (int)Math.Round(yIn1050px * BaseGame.Height / 1050.0f);
  436. }
  437. /// <summary>
  438. /// Calc rectangle, helper method to convert from our images (1024)
  439. /// to the current resolution. Everything will stay in the 16/9
  440. /// format of the textures.
  441. /// </summary>
  442. /// <param name="x">X</param>
  443. /// <param name="y">Y</param>
  444. /// <param name="width">Width</param>
  445. /// <param name="height">Height</param>
  446. /// <returns>Rectangle</returns>
  447. public static Rectangle CalcRectangle(
  448. int relX, int relY, int relWidth, int relHeight)
  449. {
  450. float widthFactor = width / 1024.0f;
  451. float heightFactor = height / 640.0f;
  452. return new Rectangle(
  453. (int)Math.Round(relX * widthFactor),
  454. (int)Math.Round(relY * heightFactor),
  455. (int)Math.Round(relWidth * widthFactor),
  456. (int)Math.Round(relHeight * heightFactor));
  457. }
  458. /// <summary>
  459. /// Calc rectangle with bounce effect, same as CalcRectangle, but sizes
  460. /// the resulting rect up and down depending on the bounceEffect value.
  461. /// </summary>
  462. /// <param name="relX">Rel x</param>
  463. /// <param name="relY">Rel y</param>
  464. /// <param name="relWidth">Rel width</param>
  465. /// <param name="relHeight">Rel height</param>
  466. /// <param name="bounceEffect">Bounce effect</param>
  467. /// <returns>Rectangle</returns>
  468. public static Rectangle CalcRectangleWithBounce(
  469. int relX, int relY, int relWidth, int relHeight, float bounceEffect)
  470. {
  471. float widthFactor = width / 1024.0f;
  472. float heightFactor = height / 640.0f;
  473. float middleX = (relX + relWidth / 2) * widthFactor;
  474. float middleY = (relY + relHeight / 2) * heightFactor;
  475. float retWidth = relWidth * widthFactor * bounceEffect;
  476. float retHeight = relHeight * heightFactor * bounceEffect;
  477. return new Rectangle(
  478. (int)Math.Round(middleX - retWidth / 2),
  479. (int)Math.Round(middleY - retHeight / 2),
  480. (int)Math.Round(retWidth),
  481. (int)Math.Round(retHeight));
  482. }
  483. /// <summary>
  484. /// Calc rectangle, same method as CalcRectangle, but keep the 4 to 3
  485. /// ratio for the image. The Rect will take same screen space in
  486. /// 16:9 and 4:3 modes. E.g. Buttons should be displayed this way.
  487. /// Should be used for 1024px width graphics.
  488. /// </summary>
  489. /// <param name="relX">Rel x</param>
  490. /// <param name="relY">Rel y</param>
  491. /// <param name="relWidth">Rel width</param>
  492. /// <param name="relHeight">Rel height</param>
  493. /// <returns>Rectangle</returns>
  494. public static Rectangle CalcRectangleKeep4To3(
  495. int relX, int relY, int relWidth, int relHeight)
  496. {
  497. float widthFactor = width / 1024.0f;
  498. float heightFactor = height / 768.0f;
  499. return new Rectangle(
  500. (int)Math.Round(relX * widthFactor),
  501. (int)Math.Round(relY * heightFactor),
  502. (int)Math.Round(relWidth * widthFactor),
  503. (int)Math.Round(relHeight * heightFactor));
  504. }
  505. /// <summary>
  506. /// Calc rectangle, same method as CalcRectangle, but keep the 4 to 3
  507. /// ratio for the image. The Rect will take same screen space in
  508. /// 16:9 and 4:3 modes. E.g. Buttons should be displayed this way.
  509. /// Should be used for 1024px width graphics.
  510. /// </summary>
  511. /// <param name="gfxRect">Gfx rectangle</param>
  512. /// <returns>Rectangle</returns>
  513. public static Rectangle CalcRectangleKeep4To3(
  514. Rectangle gfxRect)
  515. {
  516. float widthFactor = width / 1024.0f;
  517. float heightFactor = height / 768.0f;
  518. return new Rectangle(
  519. (int)Math.Round(gfxRect.X * widthFactor),
  520. (int)Math.Round(gfxRect.Y * heightFactor),
  521. (int)Math.Round(gfxRect.Width * widthFactor),
  522. (int)Math.Round(gfxRect.Height * heightFactor));
  523. }
  524. /// <summary>
  525. /// Calc rectangle for 1600px width graphics.
  526. /// </summary>
  527. /// <param name="relX">Rel x</param>
  528. /// <param name="relY">Rel y</param>
  529. /// <param name="relWidth">Rel width</param>
  530. /// <param name="relHeight">Rel height</param>
  531. /// <returns>Rectangle</returns>
  532. public static Rectangle CalcRectangle1600(
  533. int relX, int relY, int relWidth, int relHeight)
  534. {
  535. float widthFactor = width / 1600.0f;
  536. float heightFactor = (height / 1200.0f);// / (aspectRatio / (16 / 9));
  537. return new Rectangle(
  538. (int)Math.Round(relX * widthFactor),
  539. (int)Math.Round(relY * heightFactor),
  540. (int)Math.Round(relWidth * widthFactor),
  541. (int)Math.Round(relHeight * heightFactor));
  542. }
  543. /// <summary>
  544. /// Calc rectangle 2000px, just a helper to scale stuff down
  545. /// </summary>
  546. /// <param name="relX">Rel x</param>
  547. /// <param name="relY">Rel y</param>
  548. /// <param name="relWidth">Rel width</param>
  549. /// <param name="relHeight">Rel height</param>
  550. /// <returns>Rectangle</returns>
  551. public static Rectangle CalcRectangle2000(
  552. int relX, int relY, int relWidth, int relHeight)
  553. {
  554. float widthFactor = width / 2000.0f;
  555. float heightFactor = (height / 1500.0f);
  556. return new Rectangle(
  557. (int)Math.Round(relX * widthFactor),
  558. (int)Math.Round(relY * heightFactor),
  559. (int)Math.Round(relWidth * widthFactor),
  560. (int)Math.Round(relHeight * heightFactor));
  561. }
  562. /// <summary>
  563. /// Calc rectangle keep 4 to 3 align bottom
  564. /// </summary>
  565. /// <param name="relX">Rel x</param>
  566. /// <param name="relY">Rel y</param>
  567. /// <param name="relWidth">Rel width</param>
  568. /// <param name="relHeight">Rel height</param>
  569. /// <returns>Rectangle</returns>
  570. public static Rectangle CalcRectangleKeep4To3AlignBottom(
  571. int relX, int relY, int relWidth, int relHeight)
  572. {
  573. float widthFactor = width / 1024.0f;
  574. float heightFactor16To9 = height / 640.0f;
  575. float heightFactor4To3 = height / 768.0f;
  576. return new Rectangle(
  577. (int)(relX * widthFactor),
  578. (int)(relY * heightFactor16To9) -
  579. (int)Math.Round(relHeight * heightFactor4To3),
  580. (int)Math.Round(relWidth * widthFactor),
  581. (int)Math.Round(relHeight * heightFactor4To3));
  582. }
  583. /// <summary>
  584. /// Calc rectangle keep 4 to 3 align bottom right
  585. /// </summary>
  586. /// <param name="relX">Rel x</param>
  587. /// <param name="relY">Rel y</param>
  588. /// <param name="relWidth">Rel width</param>
  589. /// <param name="relHeight">Rel height</param>
  590. /// <returns>Rectangle</returns>
  591. public static Rectangle CalcRectangleKeep4To3AlignBottomRight(
  592. int relX, int relY, int relWidth, int relHeight)
  593. {
  594. float widthFactor = width / 1024.0f;
  595. float heightFactor16To9 = height / 640.0f;
  596. float heightFactor4To3 = height / 768.0f;
  597. return new Rectangle(
  598. (int)(relX * widthFactor) -
  599. (int)Math.Round(relWidth * widthFactor),
  600. (int)(relY * heightFactor16To9) -
  601. (int)Math.Round(relHeight * heightFactor4To3),
  602. (int)Math.Round(relWidth * widthFactor),
  603. (int)Math.Round(relHeight * heightFactor4To3));
  604. }
  605. /// <summary>
  606. /// Calc rectangle centered with given height.
  607. /// This one uses relX and relY points as the center for our rect.
  608. /// The relHeight is then calculated and we align everything
  609. /// with help of gfxRect (determinating the width).
  610. /// Very useful for buttons, logos and other centered UI textures.
  611. /// </summary>
  612. /// <param name="relX">Rel x</param>
  613. /// <param name="relY">Rel y</param>
  614. /// <param name="relHeight">Rel height</param>
  615. /// <param name="gfxRect">Gfx rectangle</param>
  616. /// <returns>Rectangle</returns>
  617. public static Rectangle CalcRectangleCenteredWithGivenHeight(
  618. int relX, int relY, int relHeight, Rectangle gfxRect)
  619. {
  620. float widthFactor = width / 1024.0f;
  621. float heightFactor = height / 640.0f;
  622. int rectHeight = (int)Math.Round(relHeight * heightFactor);
  623. // Keep aspect ratio
  624. int rectWidth = (int)Math.Round(
  625. gfxRect.Width * rectHeight / (float)gfxRect.Height);
  626. return new Rectangle(
  627. Math.Max(0, (int)Math.Round(relX * widthFactor) - rectWidth / 2),
  628. Math.Max(0, (int)Math.Round(relY * heightFactor) - rectHeight / 2),
  629. rectWidth, rectHeight);
  630. }
  631. /// <summary>
  632. /// Fps
  633. /// </summary>
  634. /// <returns>Int</returns>
  635. public static int Fps
  636. {
  637. get
  638. {
  639. return fpsLastSecond;
  640. }
  641. }
  642. /// <summary>
  643. /// Interpolated fps over the last 10 seconds.
  644. /// Obviously goes down if our framerate is low.
  645. /// </summary>
  646. private static float fpsInterpolated = 100.0f;
  647. /// <summary>
  648. /// Total frames
  649. /// </summary>
  650. /// <returns>Int</returns>
  651. public static int TotalFrames
  652. {
  653. get
  654. {
  655. return totalFrameCount;
  656. }
  657. }
  658. /// <summary>
  659. /// Elapsed time this frame in ms
  660. /// </summary>
  661. /// <returns>Int</returns>
  662. public static float ElapsedTimeThisFrameInMilliseconds
  663. {
  664. get
  665. {
  666. return elapsedTimeThisFrameInMs;
  667. }
  668. }
  669. /// <summary>
  670. /// Total time in seconds
  671. /// </summary>
  672. /// <returns>Int</returns>
  673. public static float TotalTime
  674. {
  675. get
  676. {
  677. return totalTimeMs / 1000.0f;
  678. }
  679. }
  680. /// <summary>
  681. /// Total time ms
  682. /// </summary>
  683. /// <returns>Float</returns>
  684. public static float TotalTimeMilliseconds
  685. {
  686. get
  687. {
  688. return totalTimeMs;
  689. }
  690. }
  691. /// <summary>
  692. /// Move factor per second, when we got 1 fps, this will be 1.0f,
  693. /// when we got 100 fps, this will be 0.01f.
  694. /// </summary>
  695. public static float MoveFactorPerSecond
  696. {
  697. get
  698. {
  699. return elapsedTimeThisFrameInMs / 1000.0f;
  700. }
  701. }
  702. /// <summary>
  703. /// World matrix
  704. /// </summary>
  705. /// <returns>Matrix</returns>
  706. public static Matrix WorldMatrix
  707. {
  708. get
  709. {
  710. return worldMatrix;
  711. }
  712. set
  713. {
  714. worldMatrix = value;
  715. // Update worldViewProj here?
  716. }
  717. }
  718. /// <summary>
  719. /// View matrix
  720. /// </summary>
  721. /// <returns>Matrix</returns>
  722. public static Matrix ViewMatrix
  723. {
  724. get
  725. {
  726. return viewMatrix;
  727. }
  728. set
  729. {
  730. // Set view matrix, usually only done in ChaseCamera.Update!
  731. viewMatrix = value;
  732. // Update camera pos and rotation, used all over the game!
  733. invViewMatrix = Matrix.Invert(viewMatrix);
  734. camPos = invViewMatrix.Translation;
  735. cameraRotation = Vector3.TransformNormal(
  736. new Vector3(0, 0, 1), invViewMatrix);
  737. }
  738. }
  739. /// <summary>
  740. /// Projection matrix
  741. /// </summary>
  742. /// <returns>Matrix</returns>
  743. public static Matrix ProjectionMatrix
  744. {
  745. get
  746. {
  747. return projectionMatrix;
  748. }
  749. set
  750. {
  751. projectionMatrix = value;
  752. // Update worldViewProj here?
  753. }
  754. }
  755. /// <summary>
  756. /// Camera pos, updated each frame in ViewMatrix!
  757. /// Public to allow easy access from everywhere, will be called a lot each
  758. /// frame, for example Model.Render uses this for distance checks.
  759. /// </summary>
  760. private static Vector3 camPos;
  761. /// <summary>
  762. /// Get camera position from inverse view matrix. Similar to method
  763. /// used in shader. Works only if ViewMatrix is correctly set.
  764. /// </summary>
  765. /// <returns>Vector 3</returns>
  766. public static Vector3 CameraPos
  767. {
  768. get
  769. {
  770. return camPos;
  771. }
  772. }
  773. /// <summary>
  774. /// Camera rotation, used to compare objects for visibility.
  775. /// </summary>
  776. private static Vector3 cameraRotation = new Vector3(0, 0, 1);
  777. /// <summary>
  778. /// Camera rotation
  779. /// </summary>
  780. /// <returns>Vector 3</returns>
  781. public static Vector3 CameraRotation
  782. {
  783. get
  784. {
  785. return cameraRotation;
  786. }
  787. }
  788. /// <summary>
  789. /// Remember inverse view matrix.
  790. /// </summary>
  791. private static Matrix invViewMatrix;
  792. /// <summary>
  793. /// Inverse view matrix
  794. /// </summary>
  795. /// <returns>Matrix</returns>
  796. public static Matrix InverseViewMatrix
  797. {
  798. get
  799. {
  800. return invViewMatrix;//Matrix.Invert(ViewMatrix);
  801. }
  802. }
  803. /// <summary>
  804. /// View projection matrix
  805. /// </summary>
  806. /// <returns>Matrix</returns>
  807. public static Matrix ViewProjectionMatrix
  808. {
  809. get
  810. {
  811. return ViewMatrix * ProjectionMatrix;
  812. }
  813. }
  814. /// <summary>
  815. /// World view projection matrix
  816. /// </summary>
  817. /// <returns>Matrix</returns>
  818. public static Matrix WorldViewProjectionMatrix
  819. {
  820. get
  821. {
  822. return WorldMatrix * ViewMatrix * ProjectionMatrix;
  823. }
  824. }
  825. /// <summary>
  826. /// Alpha blending
  827. /// </summary>
  828. public static void SetAlphaBlendingEnabled(bool value)
  829. {
  830. if (value)
  831. {
  832. Device.BlendState = BlendState.AlphaBlend;
  833. }
  834. else
  835. {
  836. Device.BlendState = BlendState.Opaque;
  837. }
  838. }
  839. /// <summary>
  840. /// Alpha modes
  841. /// </summary>
  842. public enum AlphaMode
  843. {
  844. /// <summary>
  845. /// Disable alpha blending for this (even if the texture has alpha)
  846. /// </summary>
  847. DisableAlpha,
  848. /// <summary>
  849. /// Default alpha mode: SourceAlpha and InvSourceAlpha, which does
  850. /// nothing if the texture does not have alpha, else it just displays
  851. /// it as it is (with transparent pixels).
  852. /// </summary>
  853. Default,
  854. /// <summary>
  855. /// Use source alpha one mode, this is the default mode for lighting
  856. /// effects.
  857. /// </summary>
  858. SourceAlphaOne,
  859. /// <summary>
  860. /// One one alpha mode.
  861. /// </summary>
  862. OneOne,
  863. }
  864. /// <summary>
  865. /// Current alpha mode
  866. /// </summary>
  867. public static void SetCurrentAlphaMode(AlphaMode value)
  868. {
  869. switch (value)
  870. {
  871. case AlphaMode.DisableAlpha:
  872. Device.BlendState = new BlendState()
  873. {
  874. AlphaSourceBlend = Blend.Zero,
  875. AlphaDestinationBlend = Blend.One
  876. };
  877. break;
  878. case AlphaMode.Default:
  879. Device.BlendState = new BlendState()
  880. {
  881. AlphaSourceBlend = Blend.SourceAlpha,
  882. AlphaDestinationBlend = Blend.InverseSourceAlpha
  883. };
  884. break;
  885. case AlphaMode.SourceAlphaOne:
  886. Device.BlendState = new BlendState()
  887. {
  888. AlphaSourceBlend = Blend.SourceAlpha,
  889. AlphaDestinationBlend = Blend.One
  890. };
  891. break;
  892. case AlphaMode.OneOne:
  893. Device.BlendState = new BlendState()
  894. {
  895. AlphaSourceBlend = Blend.One,
  896. AlphaDestinationBlend = Blend.One
  897. };
  898. break;
  899. }
  900. }
  901. /// <summary>
  902. /// Create base game
  903. /// </summary>
  904. /// <param name="setWindowsTitle">Set windows title</param>
  905. protected BaseGame(string setWindowsTitle)
  906. {
  907. #if GAMERSERVICES
  908. gamerServicesComponent = new GamerServicesComponent(this);
  909. base.Components.Add(gamerServicesComponent);
  910. #endif
  911. // Set graphics
  912. graphicsManager = new GraphicsDeviceManager(this);
  913. graphicsManager.GraphicsProfile = GraphicsProfile.HiDef;
  914. graphicsManager.PreparingDeviceSettings +=
  915. new EventHandler<PreparingDeviceSettingsEventArgs>(
  916. graphics_PrepareDevice);
  917. #if DEBUG
  918. // Disable vertical retrace to get highest framerates possible for
  919. // testing performance.
  920. graphicsManager.SynchronizeWithVerticalRetrace = false;
  921. #endif
  922. // Update as fast as possible, do not use fixed time steps.
  923. // The whole game is designed this way, if you remove this line
  924. // the car will not behave normal anymore!
  925. this.IsFixedTimeStep = false;
  926. // Init content manager
  927. BaseGame.content = base.Content;
  928. base.Content.RootDirectory = String.Empty;
  929. // Update windows title (used for unit testing)
  930. this.Window.Title = setWindowsTitle;
  931. this.Window.AllowUserResizing = true;
  932. remWindowsTitle = setWindowsTitle;
  933. }
  934. /// <summary>
  935. /// Empty constructor for the designer support
  936. /// </summary>
  937. protected BaseGame()
  938. : this("Game")
  939. {
  940. }
  941. void graphics_PrepareDevice(object sender, PreparingDeviceSettingsEventArgs e)
  942. {
  943. // UWP COMMENT OUT
  944. // if (Environment.OSVersion.Platform != PlatformID.Win32NT)
  945. // {
  946. // PresentationParameters presentParams =
  947. // e.GraphicsDeviceInformation.PresentationParameters;
  948. // presentParams.RenderTargetUsage = RenderTargetUsage.PlatformContents;
  949. // if (graphicsManager.PreferredBackBufferHeight == 720)
  950. // {
  951. // presentParams.MultiSampleCount = 4;
  952. //#if !DEBUG
  953. // presentParams.PresentationInterval = PresentInterval.One;
  954. //#endif
  955. // }
  956. // else
  957. // {
  958. // presentParams.MultiSampleCount = 2;
  959. //#if !DEBUG
  960. // presentParams.PresentationInterval = PresentInterval.Two;
  961. //#endif
  962. // }
  963. // }
  964. }
  965. /// <summary>
  966. /// Initialize
  967. /// </summary>
  968. protected override void Initialize()
  969. {
  970. #if !XBOX360
  971. // Add screenshot capturer. Note: Don't do this in constructor,
  972. // we need the correct window name for screenshots!
  973. this.Components.Add(new ScreenshotCapturer(this));
  974. #endif
  975. base.Initialize();
  976. GameSettings.Initialize();
  977. ApplyResolutionChange();
  978. Sound.SetVolumes(GameSettings.Default.SoundVolume,
  979. GameSettings.Default.MusicVolume);
  980. //Init the static screens
  981. Highscores.Initialize();
  982. // Replaces static Constructors with simple inits.
  983. Log.Initialize();
  984. // Set depth format
  985. backBufferDepthFormat = graphicsManager.PreferredDepthStencilFormat;
  986. // Update resolution if it changes
  987. graphicsManager.DeviceReset += graphics_DeviceReset;
  988. graphics_DeviceReset(null, EventArgs.Empty);
  989. // Create matrices for our shaders, this makes it much easier
  990. // to manage all the required matrices since there is no fixed
  991. // function support and theirfore no Device.Transform class.
  992. WorldMatrix = Matrix.Identity;
  993. // ViewMatrix is updated in camera class
  994. ViewMatrix = Matrix.CreateLookAt(
  995. new Vector3(0, 0, 250), Vector3.Zero, Vector3.Up);
  996. // Projection matrix is set by DeviceReset
  997. // Init global manager classes, which will be used all over the place ^^
  998. lineManager2D = new LineManager2D();
  999. lineManager3D = new LineManager3D();
  1000. ui = new UIRenderer();
  1001. }
  1002. /// <summary>
  1003. /// Graphics device reset handler.
  1004. /// </summary>
  1005. void graphics_DeviceReset(object sender, EventArgs e)
  1006. {
  1007. // Update width and height
  1008. width = Device.Viewport.Width;//Window.ClientBounds.Width;
  1009. height = Device.Viewport.Height;//Window.ClientBounds.Height;
  1010. aspectRatio = (float)width / (float)height;
  1011. ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
  1012. FieldOfView, aspectRatio, NearPlane, FarPlane);
  1013. // Re-Set device
  1014. // Restore z buffer state
  1015. BaseGame.Device.DepthStencilState = DepthStencilState.Default;
  1016. // Set u/v addressing back to wrap
  1017. BaseGame.Device.SamplerStates[0] = SamplerState.LinearWrap;
  1018. // Restore normal alpha blending
  1019. BaseGame.SetCurrentAlphaMode(BaseGame.AlphaMode.Default);
  1020. //TODO: AlphaTestEffect
  1021. // Set 128 and greate alpha compare for Model.Render
  1022. //BaseGame.Device.RenderState.ReferenceAlpha = 128;
  1023. //BaseGame.Device.RenderState.AlphaFunction = CompareFunction.Greater;
  1024. // Recreate all render-targets
  1025. foreach (RenderToTexture renderToTexture in remRenderToTextures)
  1026. renderToTexture.HandleDeviceReset();
  1027. }
  1028. /// <summary>
  1029. /// Epsilon (1/1000000) for comparing stuff which is nearly equal.
  1030. /// </summary>
  1031. public const float Epsilon = 0.000001f;
  1032. /// <summary>
  1033. /// Convert 3D vector to 2D vector, this is kinda the oposite of
  1034. /// GetScreenPlaneVector (not shown here). This can be useful for user
  1035. /// input/output, because we will often need the actual position on screen
  1036. /// of an object in 3D space from the users view to handle it the right
  1037. /// way. Used for lens flare and asteroid optimizations.
  1038. /// </summary>
  1039. /// <param name="point">3D world position</param>
  1040. /// <return>Resulting 2D screen position</return>
  1041. public static Point Convert3DPointTo2D(Vector3 point)
  1042. {
  1043. Vector4 result4 = Vector4.Transform(point,
  1044. ViewProjectionMatrix);
  1045. if (result4.W == 0)
  1046. result4.W = BaseGame.Epsilon;
  1047. Vector3 result = new Vector3(
  1048. result4.X / result4.W,
  1049. result4.Y / result4.W,
  1050. result4.Z / result4.W);
  1051. // Output result from 3D to 2D
  1052. return new Point(
  1053. (int)Math.Round(+result.X * (width / 2)) + (width / 2),
  1054. (int)Math.Round(-result.Y * (height / 2)) + (height / 2));
  1055. }
  1056. /// <summary>
  1057. /// Is point in front of camera?
  1058. /// </summary>
  1059. /// <param name="point">Position to check.</param>
  1060. /// <returns>Bool</returns>
  1061. public static bool IsInFrontOfCamera(Vector3 point)
  1062. {
  1063. Vector4 result = Vector4.Transform(
  1064. new Vector4(point.X, point.Y, point.Z, 1),
  1065. ViewProjectionMatrix);
  1066. // Is result in front?
  1067. return result.Z > result.W - NearPlane;
  1068. }
  1069. /// <summary>
  1070. /// Helper to check if a 3d-point is visible on the screen.
  1071. /// Will basically do the same as IsInFrontOfCamera and Convert3DPointTo2D,
  1072. /// but requires less code and is faster. Also returns just an bool.
  1073. /// Will return true if point is visble on screen, false otherwise.
  1074. /// Use the offset parameter to include points into the screen that are
  1075. /// only a couple of pixel outside of it.
  1076. /// </summary>
  1077. /// <param name="point">Point</param>
  1078. /// <param name="checkOffset">Check offset in percent of total
  1079. /// screen</param>
  1080. /// <returns>Bool</returns>
  1081. public static bool IsVisible(Vector3 point, float checkOffset)
  1082. {
  1083. Vector4 result = Vector4.Transform(
  1084. new Vector4(point.X, point.Y, point.Z, 1),
  1085. ViewProjectionMatrix);
  1086. // Point must be in front of camera, else just skip everything.
  1087. if (result.Z > result.W - NearPlane)
  1088. {
  1089. Vector2 screenPoint = new Vector2(
  1090. result.X / result.W, result.Y / result.W);
  1091. // Change checkOffset depending on how depth we are into the scene
  1092. // for very near objects (z < 5) pass all tests!
  1093. // for very far objects (z >> 5) only pass if near to +- 1.0f
  1094. float zDist = Math.Abs(result.Z);
  1095. if (zDist < 5.0f)
  1096. return true;
  1097. checkOffset = 1.0f + (checkOffset / zDist);
  1098. return
  1099. screenPoint.X >= -checkOffset && screenPoint.X <= +checkOffset &&
  1100. screenPoint.Y >= -checkOffset && screenPoint.Y <= +checkOffset;
  1101. }
  1102. // Point is not in front of camera, return false.
  1103. return false;
  1104. }
  1105. /// <summary>
  1106. /// Draw line
  1107. /// </summary>
  1108. /// <param name="startPoint">Start point</param>
  1109. /// <param name="endPoint">End point</param>
  1110. /// <param name="color">Color</param>
  1111. public static void DrawLine(Point startPoint, Point endPoint, Color color)
  1112. {
  1113. lineManager2D.AddLine(startPoint, endPoint, color);
  1114. }
  1115. /// <summary>
  1116. /// Draw line
  1117. /// </summary>
  1118. /// <param name="startPoint">Start point</param>
  1119. /// <param name="endPoint">End point</param>
  1120. public static void DrawLine(Point startPoint, Point endPoint)
  1121. {
  1122. lineManager2D.AddLine(startPoint, endPoint, Color.White);
  1123. }
  1124. /// <summary>
  1125. /// Draw line
  1126. /// </summary>
  1127. /// <param name="startPos">Start position</param>
  1128. /// <param name="endPos">End position</param>
  1129. /// <param name="color">Color</param>
  1130. public static void DrawLine(Vector3 startPos, Vector3 endPos, Color color)
  1131. {
  1132. lineManager3D.AddLine(startPos, endPos, color);
  1133. }
  1134. /// <summary>
  1135. /// Draw line
  1136. /// </summary>
  1137. /// <param name="startPos">Start position</param>
  1138. /// <param name="endPos">End position</param>
  1139. /// <param name="startColor">Start color</param>
  1140. /// <param name="endColor">End color</param>
  1141. public static void DrawLine(Vector3 startPos, Vector3 endPos,
  1142. Color startColor, Color endColor)
  1143. {
  1144. lineManager3D.AddLine(startPos, startColor, endPos, endColor);
  1145. }
  1146. /// <summary>
  1147. /// Draw line
  1148. /// </summary>
  1149. /// <param name="startPos">Start position</param>
  1150. /// <param name="endPos">End position</param>
  1151. public static void DrawLine(Vector3 startPos, Vector3 endPos)
  1152. {
  1153. lineManager3D.AddLine(startPos, endPos, Color.White);
  1154. }
  1155. /// <summary>
  1156. /// Flush line manager 2D. Renders all lines and allows more lines
  1157. /// to be rendered. Used to render lines into textures and stuff.
  1158. /// </summary>
  1159. public static void FlushLineManager2D()
  1160. {
  1161. lineManager2D.Render();
  1162. }
  1163. /// <summary>
  1164. /// Flush line manager 3D. Renders all lines and allows more lines
  1165. /// to be rendered.
  1166. /// </summary>
  1167. public static void FlushLineManager3D()
  1168. {
  1169. lineManager3D.Render();
  1170. }
  1171. /// <summary>
  1172. /// Update
  1173. /// </summary>
  1174. protected override void Update(GameTime gameTime)
  1175. {
  1176. base.Update(gameTime);
  1177. // Update all input states
  1178. Input.Update();
  1179. lastFrameTotalTimeMs = totalTimeMs;
  1180. elapsedTimeThisFrameInMs =
  1181. (float)gameTime.ElapsedGameTime.TotalMilliseconds;
  1182. totalTimeMs += elapsedTimeThisFrameInMs;
  1183. // Make sure elapsedTimeThisFrameInMs is never 0
  1184. if (elapsedTimeThisFrameInMs <= 0)
  1185. elapsedTimeThisFrameInMs = 0.001f;
  1186. // Increase frame counter for FramesPerSecond
  1187. frameCountThisSecond++;
  1188. totalFrameCount++;
  1189. // One second elapsed?
  1190. if (totalTimeMs - startTimeThisSecond > 1000.0f)
  1191. {
  1192. // Calc fps
  1193. fpsLastSecond = (int)(frameCountThisSecond * 1000.0f /
  1194. (totalTimeMs - startTimeThisSecond));
  1195. // Reset startSecondTick and repaintCountSecond
  1196. startTimeThisSecond = totalTimeMs;
  1197. frameCountThisSecond = 0;
  1198. fpsInterpolated =
  1199. MathHelper.Lerp(fpsInterpolated, fpsLastSecond, 0.1f);
  1200. // Check out if our framerate is running very low. Then we can improve
  1201. // rendering by reducing the number of objects we draw.
  1202. if (fpsInterpolated < 5)
  1203. Model.MaxViewDistance = 50;
  1204. else if (fpsInterpolated < 12)
  1205. Model.MaxViewDistance = 70;
  1206. else if (fpsInterpolated < 16)
  1207. Model.MaxViewDistance = 90;
  1208. else if (fpsInterpolated < 20)
  1209. Model.MaxViewDistance = 120;
  1210. else if (fpsInterpolated < 25)
  1211. Model.MaxViewDistance = 150;
  1212. else if (fpsInterpolated < 30 ||
  1213. HighDetail == false)
  1214. Model.MaxViewDistance = 175;
  1215. }
  1216. // Update sound and music
  1217. Sound.Update();
  1218. }
  1219. // Check if app is currently active
  1220. static bool isAppActive = true;
  1221. /// <summary>
  1222. /// Is app active
  1223. /// </summary>
  1224. /// <returns>Bool</returns>
  1225. public static bool IsAppActive
  1226. {
  1227. get
  1228. {
  1229. return isAppActive;
  1230. }
  1231. }
  1232. /// <summary>
  1233. /// On activated
  1234. /// </summary>
  1235. /// <param name="sender">Sender</param>
  1236. /// <param name="args">Arguments</param>
  1237. protected override void OnActivated(object sender, EventArgs args)
  1238. {
  1239. base.OnActivated(sender, args);
  1240. isAppActive = true;
  1241. }
  1242. /// <summary>
  1243. /// On deactivated
  1244. /// </summary>
  1245. /// <param name="sender">Sender</param>
  1246. /// <param name="args">Arguments</param>
  1247. protected override void OnDeactivated(object sender, EventArgs args)
  1248. {
  1249. base.OnDeactivated(sender, args);
  1250. isAppActive = false;
  1251. }
  1252. #if !DEBUG
  1253. int renderLoopErrorCount = 0;
  1254. #endif
  1255. /// <summary>
  1256. /// Draw
  1257. /// </summary>
  1258. /// <param name="gameTime">Game time</param>
  1259. protected override void Draw(GameTime gameTime)
  1260. {
  1261. try
  1262. {
  1263. // Clear anyway, makes unit tests easier and fixes problems if
  1264. // we don't have the z buffer cleared (some issues with line
  1265. // rendering might happen else). Performance drop is not significant!
  1266. ClearBackground();
  1267. // Get our sprites ready to draw...
  1268. Texture.additiveSprite.Begin(SpriteSortMode.Deferred, BlendState.Additive);
  1269. Texture.alphaSprite.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
  1270. // Handle custom user render code
  1271. Render();
  1272. // Render all models we remembered this frame.
  1273. meshRenderManager.Render();
  1274. // Render all 3d lines
  1275. lineManager3D.Render();
  1276. // Render UI and font texts, this also handles all collected
  1277. // screen sprites (on top of 3d game code)
  1278. UIRenderer.Render(lineManager2D);
  1279. PostUIRender();
  1280. //Handle drawing the Trophy
  1281. if (RacingGameManager.InGame && RacingGameManager.Player.Victory)
  1282. {
  1283. Texture.alphaSprite.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
  1284. int rank = GameScreens.Highscores.GetRankFromCurrentTime(
  1285. RacingGameManager.Player.LevelNum,
  1286. (int)RacingGameManager.Player.BestTimeMilliseconds);
  1287. // Show one of the trophies
  1288. BaseGame.UI.GetTrophyTexture(
  1289. // Select right one
  1290. rank == 0 ? UIRenderer.TrophyType.Gold :
  1291. rank == 1 ? UIRenderer.TrophyType.Silver :
  1292. UIRenderer.TrophyType.Bronze).
  1293. RenderOnScreen(new Rectangle(
  1294. BaseGame.Width / 2 - BaseGame.Width / 8,
  1295. BaseGame.Height / 2 - BaseGame.YToRes(10),
  1296. BaseGame.Width / 4, BaseGame.Height * 2 / 5));
  1297. Texture.alphaSprite.End();
  1298. }
  1299. ui.RenderTextsAndMouseCursor();
  1300. }
  1301. // Only catch exceptions here in release mode, when debugging
  1302. // we want to see the source of the error. In release mode
  1303. // we want to play and not be annoyed by some bugs ^^
  1304. #if !DEBUG
  1305. catch (Exception ex)
  1306. {
  1307. Log.Write("Render loop error: " + ex.ToString());
  1308. if (renderLoopErrorCount++ > 100)
  1309. throw;
  1310. }
  1311. #endif
  1312. finally
  1313. {
  1314. // Dummy block to prevent error in debug mode
  1315. }
  1316. base.Draw(gameTime);
  1317. // Apply device changes
  1318. if (mustApplyDeviceChanges)
  1319. {
  1320. graphicsManager.ApplyChanges();
  1321. mustApplyDeviceChanges = false;
  1322. }
  1323. }
  1324. /// <summary>
  1325. /// Render delegate for rendering methods, also used for many other
  1326. /// methods.
  1327. /// </summary>
  1328. public delegate void RenderHandler();
  1329. /// <summary>
  1330. /// Render
  1331. /// </summary>
  1332. protected virtual void Render()
  1333. {
  1334. }
  1335. /// <summary>
  1336. /// Post user interface rendering, in case we need it.
  1337. /// Used for rendering the car selection 3d stuff after the UI.
  1338. /// </summary>
  1339. protected virtual void PostUIRender()
  1340. {
  1341. // Overwrite this for your custom render code ..
  1342. }
  1343. /// <summary>
  1344. /// Clear background
  1345. /// </summary>
  1346. public static void ClearBackground()
  1347. {
  1348. //unsure if it clears depth correctly: Device.Clear(BackgroundColor);
  1349. Device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer,
  1350. BackgroundColor, 1.0f, 0);
  1351. }
  1352. /// <summary>
  1353. /// Remember scene render target. This is very important because
  1354. /// for our post screen shaders we have to render our whole scene
  1355. /// to this render target. But in the process we will use many other
  1356. /// shaders and they might set their own render targets and then
  1357. /// reset it, but we need to have this scene still to be set.
  1358. /// Don't reset to the back buffer (with SetRenderTarget(0, null), this
  1359. /// would stop rendering to our scene render target and the post screen
  1360. /// shader will not be able to process our screen.
  1361. /// The whole reason for this is that we can't use StrechRectangle
  1362. /// like in Rocket Commander because XNA does not provide that function
  1363. /// (the reason for that is cross platform compatibility with the XBox360).
  1364. /// Instead we could use ResolveBackBuffer, but that method is VERY SLOW.
  1365. /// Our framerate would drop from 600 fps down to 20, not good.
  1366. /// However, multisampling will not work, so we will disable it anyway!
  1367. /// </summary>
  1368. static RenderTarget2D remSceneRenderTarget = null;
  1369. /// <summary>
  1370. /// Remember the last render target we set, this way we can check
  1371. /// if the rendertarget was set before calling resolve!
  1372. /// </summary>
  1373. static RenderTarget2D lastSetRenderTarget = null;
  1374. /// <summary>
  1375. /// Remember render to texture instances to allow recreating them all
  1376. /// when DeviceReset is called.
  1377. /// </summary>
  1378. static List<RenderToTexture> remRenderToTextures =
  1379. new List<RenderToTexture>();
  1380. /// <summary>
  1381. /// Add render to texture instance to allow recreating them all
  1382. /// when DeviceReset is called with help of the remRenderToTextures list.
  1383. /// </summary>
  1384. public static void AddRemRenderToTexture(RenderToTexture renderToTexture)
  1385. {
  1386. remRenderToTextures.Add(renderToTexture);
  1387. }
  1388. /// <summary>
  1389. /// Current render target we have set, null if it is just the back buffer.
  1390. /// </summary>
  1391. public static RenderTarget2D CurrentRenderTarget
  1392. {
  1393. get
  1394. {
  1395. return lastSetRenderTarget;
  1396. }
  1397. }
  1398. /// <summary>
  1399. /// Set render target
  1400. /// </summary>
  1401. /// <param name="isSceneRenderTarget">Is scene render target</param>
  1402. internal static void SetRenderTarget(RenderTarget2D renderTarget,
  1403. bool isSceneRenderTarget)
  1404. {
  1405. Device.SetRenderTarget(renderTarget);
  1406. if (isSceneRenderTarget)
  1407. remSceneRenderTarget = renderTarget;
  1408. lastSetRenderTarget = renderTarget;
  1409. }
  1410. /// <summary>
  1411. /// Reset render target
  1412. /// </summary>
  1413. /// <param name="fullResetToBackBuffer">Full reset to back buffer</param>
  1414. internal static void ResetRenderTarget(bool fullResetToBackBuffer)
  1415. {
  1416. if (remSceneRenderTarget == null ||
  1417. fullResetToBackBuffer)
  1418. {
  1419. remSceneRenderTarget = null;
  1420. lastSetRenderTarget = null;
  1421. Device.SetRenderTarget(null);
  1422. }
  1423. else
  1424. {
  1425. Device.SetRenderTarget(remSceneRenderTarget);
  1426. lastSetRenderTarget = remSceneRenderTarget;
  1427. }
  1428. }
  1429. }
  1430. }