PageRenderTime 234ms CodeModel.GetById 109ms app.highlight 9ms RepoModel.GetById 112ms app.codeStats 0ms

/ContentSystem/Rendering/MaterialData.cs

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