#region File Description //----------------------------------------------------------------------------- // BasicEffect.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion namespace Microsoft.Xna.Framework.Graphics { /// /// Built-in effect that supports optional texturing, vertex coloring, fog, and lighting. /// public class BasicEffect : Effect, IEffectMatrices, IEffectLights, IEffectFog { #region Effect Parameters EffectParameter textureParam; EffectParameter diffuseColorParam; EffectParameter emissiveColorParam; EffectParameter specularColorParam; EffectParameter specularPowerParam; EffectParameter eyePositionParam; EffectParameter fogColorParam; EffectParameter fogVectorParam; EffectParameter worldParam; EffectParameter worldInverseTransposeParam; EffectParameter worldViewProjParam; EffectParameter shaderIndexParam; #endregion #region Fields bool lightingEnabled; bool preferPerPixelLighting; bool oneLight; bool fogEnabled; bool textureEnabled; bool vertexColorEnabled; Matrix world = Matrix.Identity; Matrix view = Matrix.Identity; Matrix projection = Matrix.Identity; Matrix worldView; Vector3 diffuseColor = Vector3.One; Vector3 emissiveColor = Vector3.Zero; Vector3 ambientLightColor = Vector3.Zero; float alpha = 1; DirectionalLight light0; DirectionalLight light1; DirectionalLight light2; float fogStart = 0; float fogEnd = 1; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; #endregion #region Public Properties /// /// Gets or sets the world matrix. /// public Matrix World { get { return world; } set { world = value; dirtyFlags |= EffectDirtyFlags.World | EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.Fog; } } /// /// Gets or sets the view matrix. /// public Matrix View { get { return view; } set { view = value; dirtyFlags |= EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.EyePosition | EffectDirtyFlags.Fog; } } /// /// Gets or sets the projection matrix. /// public Matrix Projection { get { return projection; } set { projection = value; dirtyFlags |= EffectDirtyFlags.WorldViewProj; } } /// /// Gets or sets the material diffuse color (range 0 to 1). /// public Vector3 DiffuseColor { get { return diffuseColor; } set { diffuseColor = value; dirtyFlags |= EffectDirtyFlags.MaterialColor; } } /// /// Gets or sets the material emissive color (range 0 to 1). /// public Vector3 EmissiveColor { get { return emissiveColor; } set { emissiveColor = value; dirtyFlags |= EffectDirtyFlags.MaterialColor; } } /// /// Gets or sets the material specular color (range 0 to 1). /// public Vector3 SpecularColor { get { return specularColorParam.GetValueVector3(); } set { specularColorParam.SetValue(value); } } /// /// Gets or sets the material specular power. /// public float SpecularPower { get { return specularPowerParam.GetValueSingle(); } set { specularPowerParam.SetValue(value); } } /// /// Gets or sets the material alpha. /// public float Alpha { get { return alpha; } set { alpha = value; dirtyFlags |= EffectDirtyFlags.MaterialColor; } } /// /// Gets or sets the lighting enable flag. /// public bool LightingEnabled { get { return lightingEnabled; } set { if (lightingEnabled != value) { lightingEnabled = value; dirtyFlags |= EffectDirtyFlags.ShaderIndex | EffectDirtyFlags.MaterialColor; } } } /// /// Gets or sets the per-pixel lighting prefer flag. /// public bool PreferPerPixelLighting { get { return preferPerPixelLighting; } set { if (preferPerPixelLighting != value) { preferPerPixelLighting = value; dirtyFlags |= EffectDirtyFlags.ShaderIndex; } } } /// /// Gets or sets the ambient light color (range 0 to 1). /// public Vector3 AmbientLightColor { get { return ambientLightColor; } set { ambientLightColor = value; dirtyFlags |= EffectDirtyFlags.MaterialColor; } } /// /// Gets the first directional light. /// public DirectionalLight DirectionalLight0 { get { return light0; } } /// /// Gets the second directional light. /// public DirectionalLight DirectionalLight1 { get { return light1; } } /// /// Gets the third directional light. /// public DirectionalLight DirectionalLight2 { get { return light2; } } /// /// Gets or sets the fog enable flag. /// public bool FogEnabled { get { return fogEnabled; } set { if (fogEnabled != value) { fogEnabled = value; dirtyFlags |= EffectDirtyFlags.ShaderIndex | EffectDirtyFlags.FogEnable; } } } /// /// Gets or sets the fog start distance. /// public float FogStart { get { return fogStart; } set { fogStart = value; dirtyFlags |= EffectDirtyFlags.Fog; } } /// /// Gets or sets the fog end distance. /// public float FogEnd { get { return fogEnd; } set { fogEnd = value; dirtyFlags |= EffectDirtyFlags.Fog; } } /// /// Gets or sets the fog color. /// public Vector3 FogColor { get { return fogColorParam.GetValueVector3(); } set { fogColorParam.SetValue(value); } } /// /// Gets or sets whether texturing is enabled. /// public bool TextureEnabled { get { return textureEnabled; } set { if (textureEnabled != value) { textureEnabled = value; dirtyFlags |= EffectDirtyFlags.ShaderIndex; } } } /// /// Gets or sets the current texture. /// public Texture2D Texture { get { return textureParam.GetValueTexture2D(); } set { textureParam.SetValue(value); } } /// /// Gets or sets whether vertex color is enabled. /// public bool VertexColorEnabled { get { return vertexColorEnabled; } set { if (vertexColorEnabled != value) { vertexColorEnabled = value; dirtyFlags |= EffectDirtyFlags.ShaderIndex; } } } #endregion #region Methods /// /// Creates a new BasicEffect with default parameter settings. /// public BasicEffect(GraphicsDevice device) : base(device, Resources.BasicEffect) { CacheEffectParameters(null); DirectionalLight0.Enabled = true; SpecularColor = Vector3.One; SpecularPower = 16; } /// /// Creates a new BasicEffect by cloning parameter settings from an existing instance. /// protected BasicEffect(BasicEffect cloneSource) : base(cloneSource) { CacheEffectParameters(cloneSource); lightingEnabled = cloneSource.lightingEnabled; preferPerPixelLighting = cloneSource.preferPerPixelLighting; fogEnabled = cloneSource.fogEnabled; textureEnabled = cloneSource.textureEnabled; vertexColorEnabled = cloneSource.vertexColorEnabled; world = cloneSource.world; view = cloneSource.view; projection = cloneSource.projection; diffuseColor = cloneSource.diffuseColor; emissiveColor = cloneSource.emissiveColor; ambientLightColor = cloneSource.ambientLightColor; alpha = cloneSource.alpha; fogStart = cloneSource.fogStart; fogEnd = cloneSource.fogEnd; } /// /// Creates a clone of the current BasicEffect instance. /// public override Effect Clone() { return new BasicEffect(this); } /// /// Sets up the standard key/fill/back lighting rig. /// public void EnableDefaultLighting() { LightingEnabled = true; AmbientLightColor = EffectHelpers.EnableDefaultLighting(light0, light1, light2); } /// /// Looks up shortcut references to our effect parameters. /// void CacheEffectParameters(BasicEffect cloneSource) { textureParam = Parameters["Texture"]; diffuseColorParam = Parameters["DiffuseColor"]; emissiveColorParam = Parameters["EmissiveColor"]; specularColorParam = Parameters["SpecularColor"]; specularPowerParam = Parameters["SpecularPower"]; eyePositionParam = Parameters["EyePosition"]; fogColorParam = Parameters["FogColor"]; fogVectorParam = Parameters["FogVector"]; worldParam = Parameters["World"]; worldInverseTransposeParam = Parameters["WorldInverseTranspose"]; worldViewProjParam = Parameters["WorldViewProj"]; shaderIndexParam = Parameters["ShaderIndex"]; light0 = new DirectionalLight(Parameters["DirLight0Direction"], Parameters["DirLight0DiffuseColor"], Parameters["DirLight0SpecularColor"], (cloneSource != null) ? cloneSource.light0 : null); light1 = new DirectionalLight(Parameters["DirLight1Direction"], Parameters["DirLight1DiffuseColor"], Parameters["DirLight1SpecularColor"], (cloneSource != null) ? cloneSource.light1 : null); light2 = new DirectionalLight(Parameters["DirLight2Direction"], Parameters["DirLight2DiffuseColor"], Parameters["DirLight2SpecularColor"], (cloneSource != null) ? cloneSource.light2 : null); } /// /// Lazily computes derived parameter values immediately before applying the effect. /// protected internal override void OnApply() { // Recompute the world+view+projection matrix or fog vector? dirtyFlags = EffectHelpers.SetWorldViewProjAndFog(dirtyFlags, ref world, ref view, ref projection, ref worldView, fogEnabled, fogStart, fogEnd, worldViewProjParam, fogVectorParam); // Recompute the diffuse/emissive/alpha material color parameters? if ((dirtyFlags & EffectDirtyFlags.MaterialColor) != 0) { EffectHelpers.SetMaterialColor(lightingEnabled, alpha, ref diffuseColor, ref emissiveColor, ref ambientLightColor, diffuseColorParam, emissiveColorParam); dirtyFlags &= ~EffectDirtyFlags.MaterialColor; } if (lightingEnabled) { // Recompute the world inverse transpose and eye position? dirtyFlags = EffectHelpers.SetLightingMatrices(dirtyFlags, ref world, ref view, worldParam, worldInverseTransposeParam, eyePositionParam); // Check if we can use the only-bother-with-the-first-light shader optimization. bool newOneLight = !light1.Enabled && !light2.Enabled; if (oneLight != newOneLight) { oneLight = newOneLight; dirtyFlags |= EffectDirtyFlags.ShaderIndex; } } // Recompute the shader index? if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0) { int shaderIndex = 0; if (!fogEnabled) shaderIndex += 1; if (vertexColorEnabled) shaderIndex += 2; if (textureEnabled) shaderIndex += 4; if (lightingEnabled) { if (preferPerPixelLighting) shaderIndex += 24; else if (oneLight) shaderIndex += 16; else shaderIndex += 8; } shaderIndexParam.SetValue(shaderIndex); dirtyFlags &= ~EffectDirtyFlags.ShaderIndex; } } #endregion } }