/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2014/02/01
/// 
/// @brief  カメラ周り。
/// 
/// ****************************************************************************

#pragma once

#include "CPL_DX_Kernel.h"


namespace CPL {
namespace DX {
namespace Object {


// _____________________________________________________________________________
/// @brief カメラオブジェクト
///
// *****************************************************************************
class Camera {
  friend class Graphics;

protected:
  DX::Vector3 m_vec_eye;  // 位置
  DX::Vector3 m_vec_at;   // 視点
  DX::Vector3 m_vec_up;   // 上方ベクトル

public:
  void  SetEyePos( float_cptr in_ptr_pos ){ m_vec_eye = *((DX::Vector3*)in_ptr_pos); } // カメラ座標設定
  void  SetAtPos ( float_cptr in_ptr_pos ){ m_vec_at  = *((DX::Vector3*)in_ptr_pos); } // 視点座標設定
  void  SetUpVec ( float_cptr in_ptr_vec ){ m_vec_up  = *((DX::Vector3*)in_ptr_vec); } // カメラの上方ベクトル設定
  void  SetEyePos( float x, float y, float z );
  void  SetAtPos ( float x, float y, float z );
  void  SetUpVec ( float x, float y, float z );
  void  SetEyePosX( float x ){ m_vec_eye.x = x; }
  void  SetEyePosY( float y ){ m_vec_eye.y = y; }
  void  SetEyePosZ( float z ){ m_vec_eye.z = z; }
  void  SetAtPosX ( float x ){ m_vec_at.x  = x; }
  void  SetAtPosY ( float y ){ m_vec_at.y  = y; }
  void  SetAtPosZ ( float z ){ m_vec_at.z  = z; }
  void  SetUpVecX ( float x ){ m_vec_up.x  = x; }
  void  SetUpVecY ( float y ){ m_vec_up.y  = y; }
  void  SetUpVecZ ( float z ){ m_vec_up.z  = z; }

//  void  SetupRelativeCamera   ( float_cptr posEye, float_cptr angleAtXY,  float length, float_cptr vecUp );
//  void  SetupRelativeViewpoint( float_cptr posAt,  float_cptr angleEyeXY, float length, float_cptr vecUp );

  void  MoveEyePos( float_cptr in_move ){ m_vec_eye += *((DX::Vector3*)in_move); } // カメラ座標の移動
  void  MoveEyePos( float x, float y, float z );
  void  MoveAtPos( float_cptr in_move ){ m_vec_at += *((DX::Vector3*)in_move); }
  void  MoveAtPos( float x, float y, float z );

  void               GetEyePos( float_ptr in_ptr_pos ){ *((DX::Vector3*)in_ptr_pos) = m_vec_eye; } // カメラ座標取得
  void               GetAtPos ( float_ptr in_ptr_pos ){ *((DX::Vector3*)in_ptr_pos) = m_vec_at;  } // 視点座標取得
  void               GetUpVec ( float_ptr in_ptr_vec ){ *((DX::Vector3*)in_ptr_vec) = m_vec_up;  } // カメラの上方ベクトルを取得
  DX::Vector3 const* GetEyePos()  const { return &m_vec_eye; }
  DX::Vector3 const* GetAtPos ()  const { return &m_vec_at;  }
  DX::Vector3 const* GetUpVec ()  const { return &m_vec_up;  }
  float              GetEyePosX() const { return m_vec_eye.x; }   // カメラのｘ座標取得
  float              GetEyePosY() const { return m_vec_eye.y; }   // カメラのｙ座標取得
  float              GetEyePosZ() const { return m_vec_eye.z; }   // カメラのｚ座標取得
  float              GetAtPosX()  const { return m_vec_at.x;  }   // 視点のｘ座標取得
  float              GetAtPosY()  const { return m_vec_at.y;  }   // 視点のｙ座標取得
  float              GetAtPosZ()  const { return m_vec_at.z;  }   // 視点のｚ座標取得
  float              GetUpVecX()  const { return m_vec_up.x;  }   // 上方ベクトルのｘ成分を取得
  float              GetUpVecY()  const { return m_vec_up.y;  }   // 上方ベクトルのｙ成分を取得
  float              GetUpVecZ()  const { return m_vec_up.z;  }   // 上方ベクトルのｚ成分を取得

  void  GetMatrixLH( Matrix* in_ptr_mtx_view );
  void  GetMatrixRH( Matrix* in_ptr_mtx_view );

  Camera()
    : m_vec_eye(0.0f,0.0f,-1.0f)
    , m_vec_at (0.0f,0.0f,0.0f)
    , m_vec_up (0.0f,1.0f,0.0f)
  {}
  ~Camera(){}
};



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// カメラ座標設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline
void Camera::SetEyePos( float x, float y, float z )
{
  m_vec_eye.x = x;
  m_vec_eye.y = y;
  m_vec_eye.z = z;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 視点座標設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline
void Camera::SetAtPos( float x, float y, float z )
{
  m_vec_at.x = x;
  m_vec_at.y = y;
  m_vec_at.z = z;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// カメラの上方ベクトル設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline
void Camera::SetUpVec( float x, float y, float z )
{
  m_vec_up.x = x;
  m_vec_up.y = y;
  m_vec_up.z = z;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// カメラ座標の移動
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline
void Camera::MoveEyePos( float x, float y, float z )
{
  m_vec_eye.x += x;
  m_vec_eye.y += y;
  m_vec_eye.z += z;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 視点座標の移動
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline
void Camera::MoveAtPos( float x, float y, float z )
{
  m_vec_at.x += x;
  m_vec_at.y += y;
  m_vec_at.z += z;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 左手座標系のビューマトリクスを取得する
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline
void Camera::GetMatrixLH( Matrix* in_ptr_mtx_view )
{
  Math::D3<float>::GetMatrixLookAtLH
    ( *in_ptr_mtx_view
    , m_vec_eye
    , m_vec_at
    , m_vec_up );
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 右手座標系のビューマトリクスを取得する
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline
void Camera::GetMatrixRH( Matrix* in_ptr_mtx_view )
{
  Math::D3<float>::GetMatrixLookAtRH
    ( *in_ptr_mtx_view
    , m_vec_eye
    , m_vec_at
    , m_vec_up );
}



} // namespace Object
} // namespace DX
} // namespace CPL
