PageRenderTime 70ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/ContentSystem/Rendering/MaterialData.cs

#
C# | 354 lines | 170 code | 28 blank | 156 comment | 12 complexity | 41a328377d4c3b4b53669b9d3550c0c4 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.IO;
  3. using Delta.Utilities;
  4. using Delta.Utilities.Datatypes;
  5. using Delta.Utilities.Graphics.ShaderFeatures;
  6. using Delta.Utilities.Helpers;
  7. namespace Delta.ContentSystem.Rendering
  8. {
  9. /// <summary>
  10. /// Material data for loading and saving materials through the content
  11. /// system as part of a Model or some UI scene. The actual material is
  12. /// located in the Delta.Rendering module, which uses this class. This
  13. /// class is currently used to just load the MaterialData directly via
  14. /// BinaryReader (for embedded materials in models, UI scenes, etc.).
  15. /// There are no properties or any dynamic loading in this class.
  16. /// </summary>
  17. public class MaterialData : Content, ISaveLoadBinary
  18. {
  19. #region Constants
  20. /// <summary>
  21. /// Version number for this MaterialData. If this goes above 1, we need
  22. /// to support loading older versions as well. Saving is always going
  23. /// to be the latest version (this one).
  24. /// </summary>
  25. private const int VersionNumber = 1;
  26. /// <summary>
  27. /// Default material data, do not modify, just used as fallback data.
  28. /// </summary>
  29. public static readonly MaterialData Default = new MaterialData();
  30. #endregion
  31. #region Get (Static)
  32. /// <summary>
  33. /// Get and load content based on the content name. This method makes sure
  34. /// we do not load the same content twice (the constructor is protected).
  35. /// </summary>
  36. /// <param name="contentName">Content name we want to load, this is
  37. /// passed onto the Content System, which will do the actual loading with
  38. /// help of the Load method in this class.</param>
  39. /// <returns>The loaded Content object, always unique for the same
  40. /// name, this helps comparing data.</returns>
  41. public static MaterialData Get(string contentName)
  42. {
  43. return Get<MaterialData>(contentName, ContentType.Material);
  44. }
  45. #endregion
  46. #region ShaderName (Public)
  47. /// <summary>
  48. /// Link to the shader we want to use with this material as the content
  49. /// name. If the content cannot be found or does not exist we will output
  50. /// a warning and use a fallback generated shader with the help of
  51. /// material data that is already set (e.g. diffuse map and normal map
  52. /// is set, then generate a fallback shader that can handle that).
  53. /// </summary>
  54. public string ShaderName = "";
  55. #endregion
  56. #region DiffuseMapName (Public)
  57. /// <summary>
  58. /// Diffuse map name, almost always used (else meshes look dull). For
  59. /// sky cube map shaders this is used as the sky cube map texture, which
  60. /// even can be in HDR mode if the platform supports it. If unused this
  61. /// string is empty (same goes for all other strings here), but for
  62. /// shaders that need a diffuse map (most do), this will result in using
  63. /// the default fallback image for DiffuseMap (see Image.Default)!
  64. /// </summary>
  65. public string DiffuseMapName = "";
  66. #endregion
  67. #region NormalMapName (Public)
  68. /// <summary>
  69. /// Normal map name, used for NormalMapping, only used if a normal map
  70. /// shader is used. Please note this image might have the red and alpha
  71. /// channel swapped if this is supported and wanted through shaders. This
  72. /// trick is used to increase quality of compressed normal maps, e.g. DXT1
  73. /// compresses nicely (1:6 ratio), but can look crappy for detailed normal
  74. /// maps, so DXT5 is used instead (1:4 ratio still) with R and A swapped.
  75. /// </summary>
  76. public string NormalMapName = "";
  77. #endregion
  78. #region SpecularMapName (Public)
  79. /// <summary>
  80. /// Specular map name. Gloss (specular map) mapping effect for a
  81. /// directional or point light shaders.
  82. /// </summary>
  83. public string SpecularMapName = "";
  84. #endregion
  85. #region HeightMapName (Public)
  86. /// <summary>
  87. /// Height map name, this is usually used for parallax effects and
  88. /// usually a reduced texture because we don't need much precision or
  89. /// accuracy for parallax effects. See ShaderConstants for ParallaxHeight.
  90. /// </summary>
  91. public string HeightMapName = "";
  92. #endregion
  93. #region DetailMapName (Public)
  94. /// <summary>
  95. /// Detail map name, this is almost a diffuse map with more details.
  96. /// </summary>
  97. public string DetailMapName = "";
  98. #endregion
  99. #region ReflectionCubeMapName (Public)
  100. /// <summary>
  101. /// Reflection cube map name to make reflections more shiny (uses usually
  102. /// the same sky cube map as for the sky cube rendering via DiffuseMap)
  103. /// </summary>
  104. public string ReflectionCubeMapName = "";
  105. #endregion
  106. #region LightMapName (Public)
  107. /// <summary>
  108. /// Light map name for mesh data with light mapped images baked on top.
  109. /// Only used if a light map shader is used.
  110. /// </summary>
  111. public string LightMapName = "";
  112. #endregion
  113. #region ShaderLutTexture (Public)
  114. /// <summary>
  115. /// Shader helper texture for pre-calculations. Usually used for 1D or 2D
  116. /// texture lookups for specular power and fresnel power with some extra
  117. /// pre-calculated data maybe (combined fresnel and specular, already
  118. /// applied colors, fresnel factors, etc.).
  119. /// </summary>
  120. public string ShaderLutTexture = "";
  121. #endregion
  122. #region ShadowMapTexture (Public)
  123. /// <summary>
  124. /// Texture used for performing shadow casting from given object.
  125. /// </summary>
  126. public string ShadowMapTexture = "";
  127. #endregion
  128. #region Ambient (Public)
  129. /// <summary>
  130. /// Ambient is usually always 0.15 (the default), many shaders even ignore
  131. /// this if all we want is light from light sources.
  132. /// </summary>
  133. public Color Ambient = ShaderConstants.DefaultAmbientColor;
  134. #endregion
  135. #region Diffuse (Public)
  136. /// <summary>
  137. /// The diffuse color is usually always white (90% by default), but can
  138. /// be changed from time to time to other colors. Different diffuse colors
  139. /// need a extra shader pass and cannot be merged, it is much quicker to
  140. /// let this stay white (the default) and use colored vertices for effects
  141. /// or UI, which mostly use the same atlas image, but need all kind of
  142. /// different colors per vertex!
  143. /// </summary>
  144. public Color Diffuse = ShaderConstants.DefaultDiffuseColor;
  145. #endregion
  146. ///// <summary>
  147. ///// Specular color is usually white and often even unused or optimized
  148. ///// out in shaders. Rarely used anyway (white looks best for specular).
  149. ///// </summary>
  150. //public Color Specular = DefaultSpecularColor;
  151. #region SpecularPower (Public)
  152. /// <summary>
  153. /// Specular shininess power, usually defaults to DefaultShininess.
  154. /// Sometimes not possible on low end pixel shaders, will be optimized
  155. /// out or put in the vertex shader instead.
  156. /// </summary>
  157. public float SpecularPower = ShaderConstants.DefaultSpecularPower;
  158. #endregion
  159. #region FresnelPower (Public)
  160. /// <summary>
  161. /// Fresnel power if the shader for this material does fresnel,
  162. /// fresnel bias is 0 (or bias in the shader) and the factor is 1.0 too.
  163. /// </summary>
  164. public float FresnelPower = ShaderConstants.DefaultFresnelPower;
  165. #endregion
  166. #region Constructors
  167. /// <summary>
  168. /// Create a material from content, just makes sure we use the material
  169. /// content type, all loading happens in the Load method below.
  170. /// Use the static Get method to call this.
  171. /// </summary>
  172. /// <param name="setMaterialName">
  173. /// Name for this content object, should not contain any path, project,
  174. /// scene or any special character! If this is empty or starts with an
  175. /// &gt; character, we assume this is code generated content
  176. /// (e.g. "&gt;IntroScene&lt;" or "") and no loading will happen!
  177. /// </param>
  178. protected MaterialData(string setMaterialName)
  179. : base(setMaterialName, ContentType.Material)
  180. {
  181. }
  182. /// <summary>
  183. /// Create a default material data container. All textures are empty,
  184. /// just the default color values are used. This has also no content name.
  185. /// Use the .NET 3 style constructor to assign values easily.
  186. /// </summary>
  187. public MaterialData()
  188. : base(EmptyName, ContentType.Material)
  189. {
  190. }
  191. #endregion
  192. #region ISaveLoadBinary Members
  193. /// <summary>
  194. /// Load material data from binary data stream.
  195. /// </summary>
  196. /// <param name="reader">BinaryReader for reading the data</param>
  197. public void Load(BinaryReader reader)
  198. {
  199. // We currently only support our version, if more versions are added,
  200. // we need to do different loading code depending on the version here.
  201. int version = reader.ReadInt32();
  202. if (version != VersionNumber)
  203. {
  204. Log.InvalidVersionWarning("MaterialData", version, VersionNumber);
  205. return;
  206. }
  207. ShaderName = reader.ReadString();
  208. DiffuseMapName = reader.ReadString();
  209. DetailMapName = reader.ReadString();
  210. NormalMapName = reader.ReadString();
  211. LightMapName = reader.ReadString();
  212. SpecularMapName = reader.ReadString();
  213. ReflectionCubeMapName = reader.ReadString();
  214. Ambient.Load(reader);
  215. Diffuse.Load(reader);
  216. //Specular.Load(reader);
  217. SpecularPower = reader.ReadSingle();
  218. FresnelPower = reader.ReadSingle();
  219. ShaderLutTexture = "";
  220. HeightMapName = "";
  221. try
  222. {
  223. ShaderLutTexture = reader.ReadString();
  224. // 2011-02-08: Added HeightMap
  225. HeightMapName = reader.ReadString();
  226. }
  227. catch
  228. {
  229. }
  230. }
  231. /// <summary>
  232. /// Save material data, which consists of a bunch of strings and some
  233. /// colors plus some additional settings.
  234. /// </summary>
  235. /// <param name="writer">BinaryWriter for the stream to write into</param>
  236. public void Save(BinaryWriter writer)
  237. {
  238. #region Validation
  239. // Validate strings, it is not allowed to save null, but this should
  240. // not happen anyway!
  241. if (ShaderName == null)
  242. {
  243. ShaderName = "";
  244. }
  245. if (DiffuseMapName == null)
  246. {
  247. DiffuseMapName = "";
  248. }
  249. if (NormalMapName == null)
  250. {
  251. NormalMapName = "";
  252. }
  253. /*obs
  254. if (LightMapName == null)
  255. {
  256. LightMapName = "";
  257. }
  258. */
  259. if (ReflectionCubeMapName == null)
  260. {
  261. ReflectionCubeMapName = "";
  262. }
  263. #endregion
  264. writer.Write(VersionNumber);
  265. writer.Write(ShaderName);
  266. writer.Write(DiffuseMapName);
  267. writer.Write(DetailMapName);
  268. writer.Write(NormalMapName);
  269. writer.Write(LightMapName);
  270. writer.Write(SpecularMapName);
  271. writer.Write(ReflectionCubeMapName);
  272. Ambient.Save(writer);
  273. Diffuse.Save(writer);
  274. //Specular.Save(writer);
  275. writer.Write(SpecularPower);
  276. writer.Write(FresnelPower);
  277. writer.Write(ShaderLutTexture);
  278. // 2011-02-08: Added HeightMap
  279. writer.Write(HeightMapName);
  280. }
  281. #endregion
  282. #region ToString (Public)
  283. /// <summary>
  284. /// To string
  285. /// </summary>
  286. public override string ToString()
  287. {
  288. return "MaterialData: DiffuseMapName=" + DiffuseMapName +
  289. ", NormalMapName=" + NormalMapName +
  290. ", SpecularMapName=" + SpecularMapName +
  291. //", DetailMapName=" + DetailMapName +
  292. ", LightMapName=" + LightMapName;
  293. }
  294. #endregion
  295. #region Methods (Private)
  296. #region Load
  297. /// <summary>
  298. /// Native load method, will just load the xml data.
  299. /// </summary>
  300. /// <param name="alreadyLoadedNativeData">
  301. /// The first instance that has already loaded the required content data
  302. /// of this content class or just 'null' if there is none loaded yet (or
  303. /// anymore).
  304. /// </param>
  305. protected override void Load(Content alreadyLoadedNativeData)
  306. {
  307. try
  308. {
  309. if (String.IsNullOrEmpty(RelativeFilePath) == false)
  310. {
  311. // Load via the ISaveLoadBinary interface methods below.
  312. // Cloning should not really happen for shaders anyway.
  313. FileHelper.Load(RelativeFilePath, this);
  314. }
  315. }
  316. catch (Exception ex)
  317. {
  318. Log.Warning("Failed to load material data from file '" +
  319. RelativeFilePath + "': " + ex);
  320. FailedToLoad = true;
  321. }
  322. }
  323. #endregion
  324. #endregion
  325. }
  326. }