/* * EntityModel.cs * Authors: Mike Dapiran, Karl Orosz * Copyright (c) 2007-2008 Cornell University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Util; namespace tAC_Engine.Graphics.Entities { /// /// This class defines an entity model and how it is created and rendered /// public class EntityModel : DrawableGameScreenComponent { #region Fields // The name of the rendering technique to use private string mTechniqueName = "SpecularAndDiffuse"; // The amount of color to add private Color mColorToAdd = Color.TransparentBlack; /// /// The texture's position offset in x,y form /// protected Vector2 m_TextureOffset = Vector2.Zero; /// /// Used to load Model content. /// protected string m_ModelPathName; /// /// The reference to the XNA model that the class uses. /// protected Model m_Model; /// /// The number of primatives in the model. /// protected int mPolyCount; /// /// The path name for the texture to use /// protected string mTexturePath; /// /// The texture that the model will use. /// protected Texture2D m_Texture; /// /// The path name for the alpha map. /// protected string mAlphaMapPath; /// /// How intense the specular lighting is. /// protected float m_SpecularIntensity = 0; /// /// How powerful the specular lighting is. /// protected float m_SpecularPower = 0; /// /// The transformation matrix applied to the model to scale, rotate, and translate it. /// protected Matrix m_TransformationMatrix = Matrix.Identity; /// /// The sphere encompassing the model used for collision detection /// protected BoundingSphere mBoundingSphere; /// /// The current content manager /// protected ContentManager Content; /// /// The amount of rotation along the x axis /// public float rotX; /// /// The amount of rotation along the y axis /// public float rotY; /// /// The amount of rotation along the z axis /// public float rotZ; /// /// The orientation of the model in respect to its rotation in the x, y, and z dimensions /// public Vector3 mOrientation; /// /// Dictionary of all the mesh parts to their respective texture /// public Dictionary meshTextureTexmp = new Dictionary(); /// /// Dictionary of all the mesh parts to their respective UV texture map coordinates /// public Dictionary meshTextureUVTexmp = new Dictionary(); #endregion #region Properties /// /// Gets the center position of the model /// public Vector3 Center { get { return TransformationMatrix.Translation; } } /// /// Gets the sphere encompassing the model used for collision detection /// public BoundingSphere BoundingSphere { get { return mBoundingSphere.Transform(TransformationMatrix); } } /// /// Gets the number of primatives in the model. /// public int PolyCount { get { mPolyCount = 0; foreach (ModelMesh mesh in m_Model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { mPolyCount += part.PrimitiveCount; } } return mPolyCount; } } /// /// Gets/Sets the texture's position offset in x,y form /// public Vector2 TextureOffset { get { return new Vector2((m_TextureOffset.X * m_Texture.Width), (m_TextureOffset.Y * m_Texture.Height)); } set { m_TextureOffset = new Vector2(value.X / m_Texture.Width, value.Y / m_Texture.Height); } } /// /// Gets/Sets the file path name used to load Model content. /// public string ModelPath { get { return m_ModelPathName; } set { m_ModelPathName = value; } } /// /// Gets/Sets the reference to the XNA model that the class uses. /// public Model Model { get { return m_Model; } set { m_Model = value; } } /// /// Gets/Sets the name of the rendering technique to use /// public string TechniqueName { get { return mTechniqueName; } set { mTechniqueName = value; } } /// /// Gets/Sets the texture that the model will use. /// public Texture2D Texture { get { return m_Texture; } set { m_Texture = value; } } /// /// Gets/Sets the path name for the texture to use /// public string TexturePath { get { return mTexturePath; } set { mTexturePath = value; } } /// /// Gets/Sets the path name for the alpha map. /// public string AlphaMapPath { get { return mAlphaMapPath; } set { mAlphaMapPath = value; } } /// /// Gets/Sets how intense the specular lighting is. /// public float SpecularIntensity { get { return m_SpecularIntensity; } set { m_SpecularIntensity = value; } } /// /// Gets/Sets how powerful the specular lighting is. /// public float SpecularPower { get { return m_SpecularPower; } set { m_SpecularPower = value; } } /// /// Gets/Sets the amount of color to add /// public virtual Color ColorToAdd { get { return mColorToAdd; } set { mColorToAdd = value; } } /// /// Gets/Sets the transformation matrix applied to the model to scale, rotate, and translate it. /// public virtual Matrix TransformationMatrix { get { return m_TransformationMatrix; } set { m_TransformationMatrix = value; } } #endregion #region Creation /// /// Constructor /// /// The ContentManager reference that this object will be associated with. /// The path name to the model file public EntityModel(ContentManager p_Content, string p_ModelPathName) { Content = p_Content; m_ModelPathName = p_ModelPathName; } /// /// Constructor /// /// The ContentManager reference that this object will be associated with. /// The path name to the model file /// The file path name of the texture file public EntityModel(ContentManager p_Content, string p_ModelPathName, string pTexturePathName) { Content = p_Content; m_ModelPathName = p_ModelPathName; mTexturePath = pTexturePathName; } /// /// Constructor /// /// The ContentManager reference that this object will be associated with. /// The path name to the model file /// The transformation matrix to be applied to the model public EntityModel(ContentManager p_Content, string p_ModelPathName, Matrix p_TransformationMatrix) { Content = p_Content; m_ModelPathName = p_ModelPathName; m_TransformationMatrix = p_TransformationMatrix; } /// /// Constructor /// /// The ContentManager reference that this object will be associated with. /// The path name to the model file /// The file path name of the texture file /// The transformation matrix to be applied to the model public EntityModel(ContentManager p_Content, string p_ModelPathName, string p_TexturePathName, Matrix p_TransformationMatrix) { Content = p_Content; m_ModelPathName = p_ModelPathName; m_TransformationMatrix = p_TransformationMatrix; mTexturePath = p_TexturePathName; } /// /// Constructor /// /// The ContentManager reference that this object will be associated with. /// The path name to the model file /// The file path name of the texture file /// The file path name of the alpha map file /// The transformation matrix to be applied to the model public EntityModel(ContentManager p_Content, string p_ModelPathName, string p_TexturePathName, string p_AlphaMapPathName, Matrix p_TransformationMatrix) { Content = p_Content; m_ModelPathName = p_ModelPathName; m_TransformationMatrix = p_TransformationMatrix; mTexturePath = p_TexturePathName; mAlphaMapPath = p_AlphaMapPathName; } #endregion #region Management /// /// Loads in all necessary information for content dependent objects /// protected override void LoadContent() { ReloadModel(); base.LoadContent(); } /// /// Reloads all information for the given model /// public void ReloadModel() { Model = Content.Load(m_ModelPathName); if (!string.IsNullOrEmpty(mTexturePath)) { m_Texture = Content.Load(mTexturePath); } else { m_Texture = null; } mBoundingSphere = new BoundingSphere(); foreach (ModelMesh mesh in m_Model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { BasicEffect basic = part.Effect as BasicEffect; if (basic != null) { Vector3 nontextureColor = basic.DiffuseColor; part.Effect = LightingManager.CurrentEffect.Clone(Game.GraphicsDevice); part.Effect.Parameters["inTexture"].SetValue(basic.Texture); if (mAlphaMapPath != null) { part.Effect.Parameters["alphaMap"].SetValue(Content.Load(mAlphaMapPath)); } part.Effect.Parameters["UVoffSet"].SetValue(0); part.Effect.Parameters["NonTextureColor"].SetValue(nontextureColor); } if (LightingManager.MaxShaderVersion >= ShaderProfile.PS_2_0) { part.Effect.Parameters["specularPower"].SetValue(m_SpecularPower); part.Effect.Parameters["specularIntensity"].SetValue(m_SpecularIntensity); } } mBoundingSphere = BoundingSphere.CreateMerged(mBoundingSphere, mesh.BoundingSphere); } } #endregion #region Render /// /// This is the draw method that will be called during the XNA draw cycle. /// /// The game time object passed in by XNA. public override void Draw(GameTime gameTime) { GraphicsDevice.RenderState.DepthBufferEnable = true; GraphicsDevice.RenderState.DepthBufferWriteEnable = true; GraphicsDevice.RenderState.DepthBufferFunction = CompareFunction.LessEqual; GraphicsDevice.RenderState.AlphaBlendEnable = true; GraphicsDevice.RenderState.AlphaDestinationBlend = Blend.InverseSourceAlpha; GraphicsDevice.RenderState.AlphaSourceBlend = Blend.SourceAlpha; //GraphicsDevice.RenderState.FillMode = FillMode.WireFrame m_Model.Meshes[0].Effects[0].Parameters["colorToAdd"].SetValue(mColorToAdd.ToVector4()); m_Model.Meshes[0].Effects[0].Parameters["World"].SetValue(m_TransformationMatrix); foreach (ModelMesh mesh in m_Model.Meshes) { // GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, part.StreamOffset, part.VertexStride); // GraphicsDevice.VertexDeclaration = part.VertexDeclaration; // GraphicsDevice.Indices = mesh.IndexBuffer; // GraphicsDevice.RenderState.FillMode = FillMode.Solid foreach (ModelMeshPart mmp in mesh.MeshParts) { Effect effect = mmp.Effect; mmp.Effect.CurrentTechnique = mmp.Effect.Techniques[mTechniqueName]; //This will check if a texture has been assigned to the model. //If it hasn't then it will use the texture located in the BasicEffect //for the mesh part if (m_Texture != null) { Texture2D previousModelTexture = effect.Parameters["inTexture"].GetValueTexture2D(); if (previousModelTexture != null) { meshTextureTexmp.Add(mmp, previousModelTexture); //meshTextureUVTexmp.Add(mmp, effect.Parameters["UVoffSet"].GetValueVector2()); } effect.Parameters["inTexture"].SetValue(m_Texture); //effect.Parameters["UVoffSet"].SetValue(m_TextureOffset); } //effect.Parameters["specularPower"].SetValue(m_SpecularPower); //effect.Parameters["specularIntensity"].SetValue(m_SpecularIntensity); effect.CommitChanges(); } mesh.Draw(); if (Texture != null) { foreach (ModelMeshPart mmp in mesh.MeshParts) { //Texture2D previousModelText = meshTextureTexmp[mmp]; if (meshTextureTexmp.ContainsKey(mmp)) { mmp.Effect.Parameters["inTexture"].SetValue(meshTextureTexmp[mmp]); //mmp.Effect.Parameters["UVoffSet"].SetValue(meshTextureUVTexmp[mmp]); } } meshTextureTexmp.Clear(); meshTextureUVTexmp.Clear(); } } } #endregion } }