/*
* 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
}
}