using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace MikuMikuDance.XNA.Stages
{
    /// <summary>
    /// MikuMikuDanceで用いるカメラ
    /// 仮組み。最終的にどうするかは未定。
    /// このままでもいい気もするけど……
    /// </summary>
    public class MMDCamera : GameComponent
    {
        /// <summary>
        /// カメラのポジション
        /// </summary>
        public Vector3 CameraPos { get; set; }
        /// <summary>
        /// カメラの視点
        /// </summary>
        public Vector3 CameraTarget { get; set; }
        /// <summary>
        /// カメラの上方向を表すベクトル
        /// </summary>
        public Vector3 CameraUpVector { get; set; }
        /// <summary>
        /// カメラに適応するワールド座標系
        /// </summary>
        public Matrix CameraMatrix { get; set; }
        /// <summary>
        /// 視野角
        /// </summary>
        public float FieldOfView { get; set; }
        /// <summary>
        /// Nearプレーン距離
        /// </summary>
        public float Near { get; set; }
        /// <summary>
        /// Farプレーン距離
        /// </summary>
        public float Far { get; set; }
        /// <summary>
        /// アニメーションプレイヤー
        /// </summary>
        public CameraAnimationPlayer Player { get; set; }
        /// <summary>
        /// 既定のコンストラクタ
        /// </summary>
        internal MMDCamera(Game game)
            :base(game)
        {
            CameraPos = new Vector3(0, 10, 35);
            CameraTarget = new Vector3(0, 10, 0);
            CameraUpVector = Vector3.Up;
            CameraMatrix = Matrix.Identity;
            FieldOfView = MathHelper.PiOver4;
            Near = 1.0f;
            Far = 10000.0f;
            Player = new CameraAnimationPlayer(this);
        }
        /// <summary>
        /// ビューマトリックス取得
        /// </summary>
        /// <returns>ビューマトリックス</returns>
        public Matrix GetViewMatrix()
        {
            return Matrix.CreateLookAt(Vector3.Transform(CameraPos, CameraMatrix),
                Vector3.Transform(CameraTarget, CameraMatrix), Vector3.Transform(CameraUpVector, CameraMatrix));
        }
        /// <summary>
        /// プロジェクションマトリックス取得
        /// </summary>
        /// <param name="graphics">グラフィックデバイスオブジェクト</param>
        /// <returns>プロジェクションマトリックス</returns>
        public Matrix GetProjectionMatrix(GraphicsDevice graphics)
        {
            Viewport viewport = graphics.Viewport;
            float aspectRatio = (float)viewport.Width / (float)viewport.Height;
            return Matrix.CreatePerspectiveFieldOfView(FieldOfView, aspectRatio, Near, Far);
        }
        /// <summary>
        /// カメラUpdate
        /// </summary>
        /// <param name="gameTime">ゲームタイムオブジェクト</param>
        public override void Update(GameTime gameTime)
        {
            Player.Update(-1);
        }

        long beforeTicks = 0;//前回更新tick
        internal void SetEffectParam(Effect effect, long totalTicks, GraphicsDevice graphics)
        {
            if (beforeTicks == totalTicks)
                return;//このフレームは既にセット済み
            //表示行列設定
            effect.Parameters["View"].SetValue(GetViewMatrix());
            effect.Parameters["Projection"].SetValue(GetProjectionMatrix(graphics));
            beforeTicks = totalTicks;
        }
    }
}
