using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using nkast.Aether.Animation;
using nkast.Aether.Shaders.Components;
namespace Samples.Animation
{
internal class AnimationSampleComponent : DrawableGameComponent
{
enum DrawMode : int
{
GPU,
CPU,
}
ContentManager Content;
SpriteBatch spriteBatch;
SpriteFont font;
InfiniteGridComponent grid;
Model _model_CPU;
Model _model_GPU;
Animations _animations;
DrawMode drawMode = DrawMode.GPU;
KeyboardState prevKeyboardState;
public AnimationSampleComponent(Game game) : base(game)
{
}
/// Initializes the component. Used to load non-graphical resources.
public override void Initialize()
{
Content = new ContentManager(Game.Services, "Content");
base.Initialize();
}
/// Load graphical resources needed by this component.
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load("font");
grid = new InfiniteGridComponent(GraphicsDevice, Content);
grid.Initialize();
_model_CPU = Content.Load("Dude/dude");
_model_GPU = Content.Load("Dude/dude_GPU");
_animations = _model_CPU.GetAnimations(); // Animation Data are the same between the two models
var clip = _animations.Clips["Take 001"];
_animations.SetClip(clip);
}
/// Unload graphical resources needed by this component.
protected override void UnloadContent()
{
Content.Unload();
}
/// Update the component.
/// GameTime of the Game.
public override void Update(GameTime gameTime)
{
var keyboardState = Keyboard.GetState();
var gamePadState = GamePad.GetState(PlayerIndex.One);
if ((keyboardState.IsKeyDown(Keys.Space) && prevKeyboardState.IsKeyUp(Keys.Space)) || gamePadState.Buttons.A == ButtonState.Pressed)
{
int drawModesCount = Enum.GetValues(drawMode.GetType()).Length;
drawMode = (DrawMode)(((int)drawMode + 1) % drawModesCount);
}
prevKeyboardState = keyboardState;
_animations.Update(gameTime.ElapsedGameTime, true, Matrix.Identity);
}
private Vector3 Position = Vector3.Zero;
private float Zoom = 100f;
private float RotationY = 0.0f;
private float RotationX = 0.0f;
private Matrix gameWorldRotation = Matrix.Identity;
Stopwatch sw = new Stopwatch();
double msecMin = double.MaxValue;
double msecMax = 0;
double avg = 0;
double acc = 0;
int c;
/// Draw this component.
/// The time elapsed since the last call to Draw.
public override void Draw(GameTime gameTime)
{
float aspectRatio = GraphicsDevice.Viewport.AspectRatio;
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 0.01f, 500.0f);
Matrix view = Matrix.CreateLookAt(
new Vector3(0.0f, 35.0f, -Zoom),
new Vector3(0.0f, 35.0f, 0),
Vector3.Up);
// Draw Grid
grid.Projection = projection;
grid.View = view;
//grid.EditMatrix = Matrix.Identity; // XY plane
grid.EditMatrix = Matrix.CreateFromAxisAngle(Vector3.UnitX, MathHelper.ToRadians(-90)); // XZ plane
grid.Draw(gameTime);
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
Model m = _model_CPU;
if (drawMode == DrawMode.CPU)
m = _model_CPU;
else if (drawMode == DrawMode.GPU)
m = _model_GPU;
Matrix[] transforms = new Matrix[m.Bones.Count];
m.CopyAbsoluteBoneTransformsTo(transforms);
sw.Reset();
sw.Start();
foreach (ModelMesh mesh in m.Meshes)
{
foreach (var part in mesh.MeshParts)
{
if (drawMode == DrawMode.CPU)
((BasicEffect)part.Effect).SpecularColor = Vector3.Zero;
else if (drawMode == DrawMode.GPU)
((SkinnedEffect)part.Effect).SpecularColor = Vector3.Zero;
ConfigureEffectMatrices((IEffectMatrices)part.Effect, Matrix.Identity, view, projection);
ConfigureEffectLighting((IEffectLights)part.Effect);
if (drawMode == DrawMode.CPU)
part.UpdateVertices(_animations.AnimationTransforms); // animate vertices on CPU
else if (drawMode == DrawMode.GPU)
((SkinnedEffect)part.Effect).SetBoneTransforms(_animations.AnimationTransforms);// animate vertices on GPU
}
mesh.Draw();
}
sw.Stop();
double msec = sw.Elapsed.TotalMilliseconds;
msecMin = Math.Min(msecMin, msec);
if (avg != 0)
msecMax = Math.Max(msecMax, msec);
acc += msec; c++;
if (c > 60 * 2)
{
avg = acc / c;
acc = c = 0;
}
spriteBatch.Begin();
spriteBatch.DrawString(font, "Draw Mode: " + drawMode, new Vector2(32, 32), Color.White);
spriteBatch.DrawString(font, msec.ToString("#0.000", CultureInfo.InvariantCulture) + "ms", new Vector2(32, GraphicsDevice.Viewport.Height - 130), Color.White);
spriteBatch.DrawString(font, avg.ToString("#0.000", CultureInfo.InvariantCulture) + "ms (avg)", new Vector2(32, GraphicsDevice.Viewport.Height - 100), Color.White);
spriteBatch.DrawString(font, msecMin.ToString("#0.000", CultureInfo.InvariantCulture) + "ms (min)", new Vector2(32, GraphicsDevice.Viewport.Height - 70), Color.White);
spriteBatch.DrawString(font, msecMax.ToString("#0.000", CultureInfo.InvariantCulture) + "ms (max)", new Vector2(32, GraphicsDevice.Viewport.Height - 40), Color.White);
spriteBatch.End();
}
private void ConfigureEffectMatrices(IEffectMatrices effect, Matrix world, Matrix view, Matrix projection)
{
effect.World = world;
effect.View = view;
effect.Projection = projection;
}
private void ConfigureEffectLighting(IEffectLights effect)
{
effect.EnableDefaultLighting();
effect.DirectionalLight0.Direction = Vector3.Backward;
effect.DirectionalLight0.Enabled = true;
effect.DirectionalLight1.Enabled = false;
effect.DirectionalLight2.Enabled = false;
}
}
}