/MonoGame.Framework/Graphics/Effect/BasicEffect.cs

https://bitbucket.org/refuzion/monogame · C# · 545 lines · 338 code · 112 blank · 95 comment · 30 complexity · 2c97d05fd70c5e0eb0915cb70c753195 MD5 · raw file

  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // BasicEffect.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 Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Graphics;
  12. using System;
  13. #endregion
  14. namespace Microsoft.Xna.Framework.Graphics
  15. {
  16. /// <summary>
  17. /// Built-in effect that supports optional texturing, vertex coloring, fog, and lighting.
  18. /// </summary>
  19. public class BasicEffect : Effect, IEffectMatrices, IEffectLights, IEffectFog
  20. {
  21. #region Effect Parameters
  22. EffectParameter textureParam;
  23. EffectParameter diffuseColorParam;
  24. EffectParameter emissiveColorParam;
  25. EffectParameter specularColorParam;
  26. EffectParameter specularPowerParam;
  27. EffectParameter eyePositionParam;
  28. EffectParameter fogColorParam;
  29. EffectParameter fogVectorParam;
  30. EffectParameter worldParam;
  31. EffectParameter worldInverseTransposeParam;
  32. EffectParameter worldViewProjParam;
  33. int _shaderIndex = -1;
  34. #endregion
  35. #region Fields
  36. bool lightingEnabled;
  37. bool preferPerPixelLighting;
  38. bool oneLight;
  39. bool fogEnabled;
  40. bool textureEnabled;
  41. bool vertexColorEnabled;
  42. Matrix world = Matrix.Identity;
  43. Matrix view = Matrix.Identity;
  44. Matrix projection = Matrix.Identity;
  45. Matrix worldView;
  46. Vector3 diffuseColor = Vector3.One;
  47. Vector3 emissiveColor = Vector3.Zero;
  48. Vector3 ambientLightColor = Vector3.Zero;
  49. float alpha = 1;
  50. DirectionalLight light0;
  51. DirectionalLight light1;
  52. DirectionalLight light2;
  53. float fogStart = 0;
  54. float fogEnd = 1;
  55. EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
  56. static readonly byte[] Bytecode = LoadEffectResource(
  57. #if DIRECTX
  58. "Microsoft.Xna.Framework.Graphics.Effect.Resources.BasicEffect.dx11.mgfxo"
  59. #elif PSM
  60. "MonoGame.Framework.PSMobile.PSSuite.Graphics.Resources.BasicEffect.cgx" //FIXME: This shader is totally incomplete
  61. #else
  62. "Microsoft.Xna.Framework.Graphics.Effect.Resources.BasicEffect.ogl.mgfxo"
  63. #endif
  64. );
  65. #endregion
  66. #region Public Properties
  67. /// <summary>
  68. /// Gets or sets the world matrix.
  69. /// </summary>
  70. public Matrix World
  71. {
  72. get { return world; }
  73. set
  74. {
  75. world = value;
  76. dirtyFlags |= EffectDirtyFlags.World | EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.Fog;
  77. }
  78. }
  79. /// <summary>
  80. /// Gets or sets the view matrix.
  81. /// </summary>
  82. public Matrix View
  83. {
  84. get { return view; }
  85. set
  86. {
  87. view = value;
  88. dirtyFlags |= EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.EyePosition | EffectDirtyFlags.Fog;
  89. }
  90. }
  91. /// <summary>
  92. /// Gets or sets the projection matrix.
  93. /// </summary>
  94. public Matrix Projection
  95. {
  96. get { return projection; }
  97. set
  98. {
  99. projection = value;
  100. dirtyFlags |= EffectDirtyFlags.WorldViewProj;
  101. }
  102. }
  103. /// <summary>
  104. /// Gets or sets the material diffuse color (range 0 to 1).
  105. /// </summary>
  106. public Vector3 DiffuseColor
  107. {
  108. get { return diffuseColor; }
  109. set
  110. {
  111. diffuseColor = value;
  112. dirtyFlags |= EffectDirtyFlags.MaterialColor;
  113. }
  114. }
  115. /// <summary>
  116. /// Gets or sets the material emissive color (range 0 to 1).
  117. /// </summary>
  118. public Vector3 EmissiveColor
  119. {
  120. get { return emissiveColor; }
  121. set
  122. {
  123. emissiveColor = value;
  124. dirtyFlags |= EffectDirtyFlags.MaterialColor;
  125. }
  126. }
  127. /// <summary>
  128. /// Gets or sets the material specular color (range 0 to 1).
  129. /// </summary>
  130. public Vector3 SpecularColor
  131. {
  132. get { return specularColorParam.GetValueVector3(); }
  133. set { specularColorParam.SetValue(value); }
  134. }
  135. /// <summary>
  136. /// Gets or sets the material specular power.
  137. /// </summary>
  138. public float SpecularPower
  139. {
  140. get { return specularPowerParam.GetValueSingle(); }
  141. set { specularPowerParam.SetValue(value); }
  142. }
  143. /// <summary>
  144. /// Gets or sets the material alpha.
  145. /// </summary>
  146. public float Alpha
  147. {
  148. get { return alpha; }
  149. set
  150. {
  151. alpha = value;
  152. dirtyFlags |= EffectDirtyFlags.MaterialColor;
  153. }
  154. }
  155. /// <summary>
  156. /// Gets or sets the lighting enable flag.
  157. /// </summary>
  158. public bool LightingEnabled
  159. {
  160. get { return lightingEnabled; }
  161. set
  162. {
  163. if (lightingEnabled != value)
  164. {
  165. lightingEnabled = value;
  166. dirtyFlags |= EffectDirtyFlags.ShaderIndex | EffectDirtyFlags.MaterialColor;
  167. }
  168. }
  169. }
  170. /// <summary>
  171. /// Gets or sets the per-pixel lighting prefer flag.
  172. /// </summary>
  173. public bool PreferPerPixelLighting
  174. {
  175. get { return preferPerPixelLighting; }
  176. set
  177. {
  178. if (preferPerPixelLighting != value)
  179. {
  180. preferPerPixelLighting = value;
  181. dirtyFlags |= EffectDirtyFlags.ShaderIndex;
  182. }
  183. }
  184. }
  185. /// <summary>
  186. /// Gets or sets the ambient light color (range 0 to 1).
  187. /// </summary>
  188. public Vector3 AmbientLightColor
  189. {
  190. get { return ambientLightColor; }
  191. set
  192. {
  193. ambientLightColor = value;
  194. dirtyFlags |= EffectDirtyFlags.MaterialColor;
  195. }
  196. }
  197. /// <summary>
  198. /// Gets the first directional light.
  199. /// </summary>
  200. public DirectionalLight DirectionalLight0 { get { return light0; } }
  201. /// <summary>
  202. /// Gets the second directional light.
  203. /// </summary>
  204. public DirectionalLight DirectionalLight1 { get { return light1; } }
  205. /// <summary>
  206. /// Gets the third directional light.
  207. /// </summary>
  208. public DirectionalLight DirectionalLight2 { get { return light2; } }
  209. /// <summary>
  210. /// Gets or sets the fog enable flag.
  211. /// </summary>
  212. public bool FogEnabled
  213. {
  214. get { return fogEnabled; }
  215. set
  216. {
  217. if (fogEnabled != value)
  218. {
  219. fogEnabled = value;
  220. dirtyFlags |= EffectDirtyFlags.ShaderIndex | EffectDirtyFlags.FogEnable;
  221. }
  222. }
  223. }
  224. /// <summary>
  225. /// Gets or sets the fog start distance.
  226. /// </summary>
  227. public float FogStart
  228. {
  229. get { return fogStart; }
  230. set
  231. {
  232. fogStart = value;
  233. dirtyFlags |= EffectDirtyFlags.Fog;
  234. }
  235. }
  236. /// <summary>
  237. /// Gets or sets the fog end distance.
  238. /// </summary>
  239. public float FogEnd
  240. {
  241. get { return fogEnd; }
  242. set
  243. {
  244. fogEnd = value;
  245. dirtyFlags |= EffectDirtyFlags.Fog;
  246. }
  247. }
  248. /// <summary>
  249. /// Gets or sets the fog color.
  250. /// </summary>
  251. public Vector3 FogColor
  252. {
  253. get { return fogColorParam.GetValueVector3(); }
  254. set { fogColorParam.SetValue(value); }
  255. }
  256. /// <summary>
  257. /// Gets or sets whether texturing is enabled.
  258. /// </summary>
  259. public bool TextureEnabled
  260. {
  261. get { return textureEnabled; }
  262. set
  263. {
  264. if (textureEnabled != value)
  265. {
  266. textureEnabled = value;
  267. dirtyFlags |= EffectDirtyFlags.ShaderIndex;
  268. }
  269. }
  270. }
  271. /// <summary>
  272. /// Gets or sets the current texture.
  273. /// </summary>
  274. public Texture2D Texture
  275. {
  276. get { return textureParam.GetValueTexture2D(); }
  277. set { textureParam.SetValue(value); }
  278. }
  279. /// <summary>
  280. /// Gets or sets whether vertex color is enabled.
  281. /// </summary>
  282. public bool VertexColorEnabled
  283. {
  284. get { return vertexColorEnabled; }
  285. set
  286. {
  287. if (vertexColorEnabled != value)
  288. {
  289. vertexColorEnabled = value;
  290. dirtyFlags |= EffectDirtyFlags.ShaderIndex;
  291. }
  292. }
  293. }
  294. #endregion
  295. #region Methods
  296. /// <summary>
  297. /// Creates a new BasicEffect with default parameter settings.
  298. /// </summary>
  299. public BasicEffect(GraphicsDevice device)
  300. : base(device, Bytecode)
  301. {
  302. CacheEffectParameters(null);
  303. DirectionalLight0.Enabled = true;
  304. SpecularColor = Vector3.One;
  305. SpecularPower = 16;
  306. }
  307. /// <summary>
  308. /// Creates a new BasicEffect by cloning parameter settings from an existing instance.
  309. /// </summary>
  310. protected BasicEffect(BasicEffect cloneSource)
  311. : base(cloneSource)
  312. {
  313. CacheEffectParameters(cloneSource);
  314. lightingEnabled = cloneSource.lightingEnabled;
  315. preferPerPixelLighting = cloneSource.preferPerPixelLighting;
  316. fogEnabled = cloneSource.fogEnabled;
  317. textureEnabled = cloneSource.textureEnabled;
  318. vertexColorEnabled = cloneSource.vertexColorEnabled;
  319. world = cloneSource.world;
  320. view = cloneSource.view;
  321. projection = cloneSource.projection;
  322. diffuseColor = cloneSource.diffuseColor;
  323. emissiveColor = cloneSource.emissiveColor;
  324. ambientLightColor = cloneSource.ambientLightColor;
  325. alpha = cloneSource.alpha;
  326. fogStart = cloneSource.fogStart;
  327. fogEnd = cloneSource.fogEnd;
  328. }
  329. /// <summary>
  330. /// Creates a clone of the current BasicEffect instance.
  331. /// </summary>
  332. public override Effect Clone()
  333. {
  334. return new BasicEffect(this);
  335. }
  336. /// <summary>
  337. /// Sets up the standard key/fill/back lighting rig.
  338. /// </summary>
  339. public void EnableDefaultLighting()
  340. {
  341. LightingEnabled = true;
  342. AmbientLightColor = EffectHelpers.EnableDefaultLighting(light0, light1, light2);
  343. }
  344. /// <summary>
  345. /// Looks up shortcut references to our effect parameters.
  346. /// </summary>
  347. void CacheEffectParameters(BasicEffect cloneSource)
  348. {
  349. textureParam = Parameters["Texture"];
  350. diffuseColorParam = Parameters["DiffuseColor"];
  351. emissiveColorParam = Parameters["EmissiveColor"];
  352. specularColorParam = Parameters["SpecularColor"];
  353. specularPowerParam = Parameters["SpecularPower"];
  354. eyePositionParam = Parameters["EyePosition"];
  355. fogColorParam = Parameters["FogColor"];
  356. fogVectorParam = Parameters["FogVector"];
  357. worldParam = Parameters["World"];
  358. worldInverseTransposeParam = Parameters["WorldInverseTranspose"];
  359. worldViewProjParam = Parameters["WorldViewProj"];
  360. light0 = new DirectionalLight(Parameters["DirLight0Direction"],
  361. Parameters["DirLight0DiffuseColor"],
  362. Parameters["DirLight0SpecularColor"],
  363. (cloneSource != null) ? cloneSource.light0 : null);
  364. light1 = new DirectionalLight(Parameters["DirLight1Direction"],
  365. Parameters["DirLight1DiffuseColor"],
  366. Parameters["DirLight1SpecularColor"],
  367. (cloneSource != null) ? cloneSource.light1 : null);
  368. light2 = new DirectionalLight(Parameters["DirLight2Direction"],
  369. Parameters["DirLight2DiffuseColor"],
  370. Parameters["DirLight2SpecularColor"],
  371. (cloneSource != null) ? cloneSource.light2 : null);
  372. }
  373. /// <summary>
  374. /// Lazily computes derived parameter values immediately before applying the effect.
  375. /// </summary>
  376. protected internal override bool OnApply()
  377. {
  378. // Recompute the world+view+projection matrix or fog vector?
  379. dirtyFlags = EffectHelpers.SetWorldViewProjAndFog(dirtyFlags, ref world, ref view, ref projection, ref worldView, fogEnabled, fogStart, fogEnd, worldViewProjParam, fogVectorParam);
  380. // Recompute the diffuse/emissive/alpha material color parameters?
  381. if ((dirtyFlags & EffectDirtyFlags.MaterialColor) != 0)
  382. {
  383. EffectHelpers.SetMaterialColor(lightingEnabled, alpha, ref diffuseColor, ref emissiveColor, ref ambientLightColor, diffuseColorParam, emissiveColorParam);
  384. dirtyFlags &= ~EffectDirtyFlags.MaterialColor;
  385. }
  386. if (lightingEnabled)
  387. {
  388. // Recompute the world inverse transpose and eye position?
  389. dirtyFlags = EffectHelpers.SetLightingMatrices(dirtyFlags, ref world, ref view, worldParam, worldInverseTransposeParam, eyePositionParam);
  390. // Check if we can use the only-bother-with-the-first-light shader optimization.
  391. bool newOneLight = !light1.Enabled && !light2.Enabled;
  392. if (oneLight != newOneLight)
  393. {
  394. oneLight = newOneLight;
  395. dirtyFlags |= EffectDirtyFlags.ShaderIndex;
  396. }
  397. }
  398. // Recompute the shader index?
  399. if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0)
  400. {
  401. int shaderIndex = 0;
  402. if (!fogEnabled)
  403. shaderIndex += 1;
  404. if (vertexColorEnabled)
  405. shaderIndex += 2;
  406. if (textureEnabled)
  407. shaderIndex += 4;
  408. if (lightingEnabled)
  409. {
  410. if (preferPerPixelLighting)
  411. shaderIndex += 24;
  412. else if (oneLight)
  413. shaderIndex += 16;
  414. else
  415. shaderIndex += 8;
  416. }
  417. dirtyFlags &= ~EffectDirtyFlags.ShaderIndex;
  418. #if PSM
  419. #warning Major hack as PSM Shaders don't support multiple Techinques (yet)
  420. shaderIndex = 0;
  421. #endif
  422. if (_shaderIndex != shaderIndex)
  423. {
  424. _shaderIndex = shaderIndex;
  425. CurrentTechnique = Techniques[_shaderIndex];
  426. return true;
  427. }
  428. }
  429. return false;
  430. }
  431. #endregion
  432. }
  433. }