/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2014/01/24
/// 
/// @brief  ３Ｄ数学系
/// 
/// ****************************************************************************

#pragma once

#include "CPL_MathBase.h"


namespace CPL {
namespace Math {

template<class T_Type = float>
class D3 {
  typedef T_Type*       type_ptr;
  typedef T_Type const* type_cptr;
public:


  // _____________________________________________________________________________
  /// @brief ベクトルクラス
  ///
  // *****************************************************************************
  template<class T_Type>
  class Vector_
    : public Core::Point3<T_Type>
  {
    typedef Core::Point3<T_Type> type_base;
  public:
    operator type_ptr()        { return &this->get(); }
    operator type_cptr() const { return &this->get(); }
    Vector_(){};
    Vector_( type_cptr p )                     : type_base( p[0], p[1], p[2] ) {}
    Vector_( T_Type x, T_Type y, T_Type z )    : type_base( x, y, z ) {}
    Vector_( const Core::Point3<T_Type>& vec ) : type_base( vec ) {}
    Vector_( const Vector_& vec )              : type_base( vec ) {}
    template<class T_Vec>
    Vector_( T_Vec const& in_vector )
      : type_base( static_cast<T_Type const*>(&in_vector.get()) )
    {}

    //typedef Vector_*        ptr;
    //typedef Vector_ const* cptr;
    //typedef Vector_&        ref;
    //typedef Vector_ const& cref;
  };
  typedef Vector_<T_Type> Vector;


  // _____________________________________________________________________________
  /// @brief ラインクラス　（２つの座標）
  ///
  // *****************************************************************************
  typedef baseLine_T<Vector> Line;


  // _____________________________________________________________________________
  /// @brief ポリゴンクラス
  ///
  // *****************************************************************************
  typedef baseTriangle_T<Vector> Triangle;


  // _____________________________________________________________________________
  /// @brief 平面を表すクラス
  ///
  // *****************************************************************************
  class Plane
    : public Core::BaseObject
  {
  public:
    union {
      struct {
        T_Type a, b, c, d;
      };
      T_Type n[3];
    };

    Plane() : a(0), b(0), c(0), d(0) {}
    Plane( T_Type a_, T_Type b_, T_Type c_, T_Type d_ )
    {
      a = a_; b = b_; c = c_; d = d_;
    }
    // ３点から平面を作成
    Plane( type_cptr p0, type_cptr p1, type_cptr p2 )
    {
      compute( p0, p1, p2 );
    }
    //
    Plane( const Triangle& tri )
    {
      compute( tri.p0, tri.p1, tri.p2 );
    }

    operator type_ptr(){ return &a; }
    operator type_cptr() const { return &a; }

  private:
    void compute( type_cptr p0, type_cptr p1, type_cptr p2 )
    {
      T_Type tmp[3];
      const Vector& v0 = *reinterpret_cast<const Vector*>(p0);
      const Vector& v1 = *reinterpret_cast<const Vector*>(p1);
      const Vector& v2 = *reinterpret_cast<const Vector*>(p2);
      GetVecNormalize( n, GetVecCross( tmp, v1-v0, v2-v0 ) );
      d = GetVecDot( n, v0 );
    }
  };


  
  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルコピー
  ///
  /// @param[out] out_vector
  ///   : コピー先の３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector
  ///   : コピー元の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return なし。
  ///
  /// @note 
  /// out_vector = in_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void VecCopy( type_ptr out_vector, type_cptr in_vector )
  {
    VecCopy_<T_Type,3>( out_vector, in_vector );
  }



  // _____________________________________________________________________________
  /// @brief ４×４マトリクスのコピー
  ///
  /// @param[out] out_matrix
  ///   : コピー先のマトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : コピー元のマトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixCopy( type_ptr out_matrix, type_cptr in_matrix )
  {
    VecCopy_<T_Type,16>( out_matrix, in_matrix );
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルの長さの２乗を取得
  ///
  /// @param[in] in_vector : ３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return 各辺の２乗の和を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecLengthSq( type_cptr in_vector )
  {
    return Squ(in_vector[0]) + Squ(in_vector[1]) + Squ(in_vector[2]);
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルの長さの２乗を取得
  ///
  /// @param[in] in_X : ３Ｄベクトルのｘ成分を指定します。
  /// @param[in] in_Y : ３Ｄベクトルのｙ成分を指定します。
  /// @param[in] in_Z : ３Ｄベクトルのｚ成分を指定します。
  ///
  /// @return 各辺の２乗の和を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecLengthSq( T_Type in_X, T_Type in_Y, T_Type in_Z )
  {
    return Squ(in_X) + Squ(in_Y) + Squ(in_Z);
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルの長さを取得
  ///
  /// @param[in] in_vector : ３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// 
  /// @return ３Ｄベクトルの長さを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecLength( type_cptr in_vector )
  {
    return sqrtf( GetVecLengthSq(in_vector) );
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルの長さを取得
  ///
  /// @param[in] in_X : ３Ｄベクトルのｘ成分を指定します。
  /// @param[in] in_Y : ３Ｄベクトルのｙ成分を指定します。
  /// @param[in] in_Z : ３Ｄベクトルのｚ成分を指定します。
  ///
  /// @return ３Ｄベクトルの長さを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecLength( T_Type in_X, T_Type in_Y, T_Type in_Z )
  {
    return sqrtf( GetVecLengthSq(in_X,in_Y,in_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ベクトルを加算したものを取得
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vectorA
  ///   : 計算元データ列への３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vectorB
  ///   : 加算データ列への３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  ///
  /// @note 
  /// out_vector = in_vectorA + in_vectorB
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecAdd( type_ptr out_vector, type_cptr in_vectorA, type_cptr in_vectorB )
  {
    return GetVecAdd_<T_Type,3>( out_vector, in_vectorA, in_vectorB );
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルを加算
  ///
  /// @param[in,out] io_vector
  ///   : 計算元の３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector_for_add
  ///   : 加算する３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void VecAdd( type_ptr io_vector, type_cptr in_vector_for_add )
  {
    GetVecAdd_<T_Type,3>( io_vector, io_vector, in_vector_for_add );
  }




  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルを減算したものを取得
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する３Ｄベクトル（先頭の成分のアドレス）渡します。
  /// @param[in] in_vectorB
  ///   : 計算元の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vectorC
  ///   : 減算する３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  ///
  /// @note
  /// out_vector = in_vectorB - in_vectorC
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecSub( type_ptr out_vector, type_cptr in_vectorB, type_cptr in_vectorC )
  {
    return GetVecSub_<T_Type,3>( out_vector, in_vectorB, in_vectorC );
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルを減算
  ///
  /// @param[in,out] io_vector
  ///   : 計算元の３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector_for_sub
  ///   : 加算する３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @note 
  /// io_vector -= in_vector_for_sub
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void VecSub( type_ptr io_vector, type_cptr in_vector_for_sub )
  {
    GetVecSub_<T_Type,3>( io_vector, io_vector, in_vector_for_sub );
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄ単位ベクトルを取得
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する３Ｄベクトル（先頭の成分のアドレス）渡します。
  /// @param[in] in_vector
  ///   : 計算元の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  ///
  /// @note
  /// out_vector = in_vector / length
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecNormalize( type_ptr out_vector, type_cptr in_vector )
  {
    T_Type len = GetVecLength(in_vector);
    if( len != 0 )
    {
      T_Type a = static_cast<T_Type>(1) / len;
      out_vector[0] = in_vector[0] * a;
      out_vector[1] = in_vector[1] * a;
      out_vector[2] = in_vector[2] * a;
    }
    return out_vector;
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄ単位ベクトルに変換
  ///
  /// @param[in,out] io_vector
  ///   : 変換する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// 
  /// @return なし。
  ///
  /// @note 
  /// io_vector /= length
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void VecNormalize( type_ptr io_vector )
  {
    if( AllZero_<T_Type,3>( io_vector ) )
    {
      io_vector[0] = io_vector[2] = static_cast<T_Type>(0.0);
      io_vector[1] = static_cast<T_Type>(1);
    }
    else
    {
      T_Type a = static_cast<T_Type>(1) / GetVecLength( io_vector );
      io_vector[0] *= a;
      io_vector[1] *= a;
      io_vector[2] *= a;
    }
  }




  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルの内積を取得
  ///
  /// ２つのベクトルの角度がθのときのcosθを返す。
  ///
  /// @param[in] in_vectorA : １番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vectorB : ２番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return in_vectorA と in_vectorB の内積を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecDot( type_cptr in_vectorA, type_cptr in_vectorB )
  {
    return in_vectorA[0]*in_vectorB[0] + in_vectorA[1]*in_vectorB[1] + in_vectorA[2]*in_vectorB[2];
  }




  // _____________________________________________________________________________
  /// @brief 外積を取得
  ///
  /// @param[out] out_vector : 取得用３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in]  in_vectorA  : １番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in]  in_vectorB  : ２番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  ///
  /// @note
  /// △ABCがあったとき、辺ABと辺ACの外積を取れば法線となる。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecCross
      ( type_ptr  out_vector
      , type_cptr in_vectorA
      , type_cptr in_vectorB
      )
  {
    out_vector[0] = in_vectorA[1] * in_vectorB[2] - in_vectorA[2] * in_vectorB[1];
    out_vector[1] = in_vectorA[2] * in_vectorB[0] - in_vectorA[0] * in_vectorB[2];
    out_vector[2] = in_vectorA[0] * in_vectorB[1] - in_vectorA[1] * in_vectorB[0];
    return out_vector;
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルの正規化
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する３Ｄベクトル（先頭の成分のアドレス）渡します。
  /// @param[in]  in_pos0 : １番目の３Ｄ座標（先頭の成分のアドレス）を指定します。
  /// @param[in]  in_pos1 : ２番目の３Ｄ座標（先頭の成分のアドレス）を指定します。
  /// @param[in]  in_pos2 : ３番目の３Ｄ座標（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetNormal3p
      ( type_ptr  out_vector
      , type_cptr in_pos0
      , type_cptr in_pos1
      , type_cptr in_pos2
      )
  {
    T_Type v0[3] =
    { in_pos1[0] - in_pos0[0]
    , in_pos1[1] - in_pos0[1]
    , in_pos1[2] - in_pos0[2]
    };
    T_Type v1[3] =
    { in_pos2[0] - in_pos0[0]
    , in_pos2[1] - in_pos0[1]
    , in_pos2[2] - in_pos0[2]
    };
    return GetVecCross( out_vector, v0, v1 );
  }


  // _____________________________________________________________________________
  /// @brief ２つの３Ｄベクトル間の角度の取得
  ///
  /// @param[in] in_vectorA : １番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vectorB : ２番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return in_vectorAとin_vectorBの角度（radian単位）
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecAngle( type_cptr in_vectorA, type_cptr in_vectorB )
  {
    T_Type len_v0 = GetVecLength(in_vectorA);
    T_Type len_v1 = GetVecLength(in_vectorB);
    return acosf( GetVecDot( in_vectorA, in_vectorB ) / (len_v0 * len_v1) );
  }


  // _____________________________________________________________________________
  /// @brief ３重積の取得
  ///
  /// @param[in] in_vectorA : １番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vectorB : ２番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vectorC : ３番目の３Ｄベクトル（先頭の成分のアドレス）を指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type
    GetScalarTriple
      ( type_cptr in_vectorA
      , type_cptr in_vectorB
      , type_cptr in_vectorC
      )
  {
    T_Type tmp[3];
    return GetVecDot( in_vectorA, GetVecCross( tmp, in_vectorB, in_vectorC ) );
  }


  // _____________________________________________________________________________
  /// @brief 平面から点への最近接点を取得
  ///
  /// @param[out] out_vector
  ///   : 最近接点の座標を格納する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_point
  ///   : 点の座標となる３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_plane
  ///   : 平面（Plane参照）を指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecClosestPointPlane
      ( type_ptr  out_vector
      , type_cptr in_point
      , type_cptr in_plane
      )
  {
    const Vector& xyz   = *reinterpret_cast<const Vector*>(in_point);
    const Plane&  plane = *reinterpret_cast<const Plane*>(in_plane);

    T_Type t = (GetVecDot(plane.n, xyz) - plane.d) / GetVecDot( plane.n, plane.n );

    out_vector[0] = xyz.x - plane.n[0] * t;
    out_vector[1] = xyz.y - plane.n[1] * t;
    out_vector[2] = xyz.z - plane.n[2] * t;

    return out_vector;
  }


  // _____________________________________________________________________________
  /// @brief 線分から点への最近接点を取得
  ///
  /// @param[out] out_vector
  ///   : 最近接点の座標を格納する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_point
  ///   : 点の座標となる３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_seg0
  ///   : 線分の始端座標となる３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_seg1
  ///   : 線分の終端座標となる３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecClosestPointSegment
      ( type_ptr  out_vector
      , type_ptr  in_point
      , type_cptr in_seg0
      , type_cptr in_seg1
      )
  {
    const Vector& a = *reinterpret_cast<const Vector*>(in_seg0);
    const Vector& b = *reinterpret_cast<const Vector*>(in_seg1);
    const Vector& c  = *reinterpret_cast<const Vector*>(in_point);

    Vector ab = b - a;
    // パラメータ化されている位置の計算によりvsegにxyzを射影
    T_Type t = GetVecDot( c - a, ab ) / GetVecDot( ab, ab );
    // 線分の外側にある場合、ｔを最近接点までクランプ
    CPL::Clamp( t, (T_Type)0, (T_Type)1 );
    // クランプされているｔからの射影されている位置を計算
    *reinterpret_cast<Vector*>(out_vector) = a + ab * t;

    return out_vector;
  }


  // _____________________________________________________________________________
  /// @brief 平面と線分との交差判定
  ///
  /// @param[out] out_vector
  ///   : 交差点の座標を格納する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_plane
  ///   : 平面（Plane参照）を指定します。
  /// @param[in] in_seg0
  ///   : 線分の始端座標となる３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_seg1
  ///   : 線分の終端座標となる３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return
  /// 交点が存在しない場合はnullptrを返します。\n
  /// 存在する場合はout_vectorを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecIntersectSegmentPlane
      ( type_ptr  out_vector
      , type_cptr in_plane
      , type_cptr in_seg0
      , type_cptr in_seg1
      )
  {
    const Plane& plane = *reinterpret_cast<const Plane*>(in_plane);
    const Vector& va = *reinterpret_cast<const Vector*>(in_seg0);
    const Vector& vb = *reinterpret_cast<const Vector*>(in_seg1);
    const Vector vab = vb - va;
    // 方向のあるレイに対して平面と交差するtの値を計算
    T_Type t = (plane.d - GetVecDot( plane.n, va )) / GetVecDot( plane.n, vab );

    // tが０〜１の中にある場合は交差点を返す
    if( 0.0f <= t  &&  t <= 1.0f )
    {
      *reinterpret_cast<Vector*>(out_vector) = va + vab * t;
      return out_vector;
    }
    return nullptr;
  }


  // _____________________________________________________________________________
  /// @brief ３点ポリゴンと線分との交点（重心座標）を取得
  ///
  /// @param[out] out_vector
  ///   : 重心座標を格納する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_triangle_posA
  ///   : 三角形(abc)の頂点座標ａの３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_triangle_posB
  ///   : 三角形(abc)の頂点座標ｂの３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_triangle_posC
  ///   : 三角形(abc)の頂点座標ｃの３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_segment_posA
  ///   : 線分の始端座標の３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_segment_posB
  ///   : 線分の終端座標の３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_hit_type
  ///   : 面判定フラグを指定します。\n 0:両面　1:表のみ　-1:裏のみ。
  ///
  /// @return
  /// 交点が存在していない場合はnullptrを返す。\n
  /// 存在する場合はout_vectorのポインタを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecIntersectSegmentTriangle
      ( type_ptr  out_vector
      , type_cptr in_triangle_posA
      , type_cptr in_triangle_posB
      , type_cptr in_triangle_posC
      , type_cptr in_segment_posA
      , type_cptr in_segment_posB
      , int       in_hit_type
      )
  {
    const Vector& a = *reinterpret_cast<const Vector*>(in_triangle_posA);
    const Vector& b = *reinterpret_cast<const Vector*>((in_hit_type == -1) ? in_triangle_posC : in_triangle_posB);
    const Vector& c = *reinterpret_cast<const Vector*>((in_hit_type == -1) ? in_triangle_posB : in_triangle_posC);
    const Vector& p = *reinterpret_cast<const Vector*>(in_segment_posA);
    const Vector& q = *reinterpret_cast<const Vector*>(in_segment_posB);

    Vector ab = b - a;
    Vector ac = c - a;
    Vector qp = p - q;
    // 三角形の法線を計算
    Vector n;
    GetVecCross( n, ab, ac );

    // 分母dを計算
    // d <= 0の場合、線分は三角形に平行か、離れていく方向を指すので早期に終了
    T_Type d = GetVecDot( qp, n );

    if     ( in_hit_type == 0 ){ d = Abs(d); }
    else if( in_hit_type == 2 ){ d = -d; }

    if( d <= 0 ){ return nullptr; }

    // vsegと三角形の平面の交差の値tを計算
    // 線分は0<=t<=1の場合に交差。（光線は0 <= t）
    // 交差が三角形を貫通することが分かるまでdによる除算を遅延
    Vector ap = p - a;
    T_Type t = GetVecDot( ap, n );
    if( t < 0  ||  d < t )
    {
      return nullptr;
    }

    // 重心座標の成分を計算し、範囲内にあるかどうか判定
    Vector e;
    GetVecCross( e, qp, ap );
    T_Type v, w;

    if( in_hit_type == 0 ) // 両面判定
    {
      v = Abs( GetVecDot( ac, e ) );
      if( d < v )
      {
        return nullptr;
      }
      w = Abs( GetVecDot( ab, e ) );
      if( d < v+w )
      {
        return nullptr;
      }
    }
    else
    {
      v = GetVecDot( ac, e );
      if( v < 0.0  ||  d < v )
      {
        return nullptr;
      }
      w = -GetVecDot( ab, e );
      if( w < 0.0  ||  d < v+w )
      {
        return nullptr;
      }
    }

    // 線分は三角形と交差
    T_Type ood = 1 / d;
    out_vector[1] = v * ood;
    out_vector[2] = w * ood;
    out_vector[0] = 1 - out_vector[1] - out_vector[2];

    return out_vector;
  }



  // _____________________________________________________________________________
  /// @brief 球とレイとの交差判定
  ///
  /// @param[out] out_vector
  ///   : 座標を格納する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_center
  ///   : 球の中心座標の３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_r
  ///   : 球の半径を指定します。
  /// @param[in] in_ray_pos0
  ///   : 直線の始点座標の３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_ray_pos1
  ///   : 直線の終点座標の３Ｄベクトル（先頭の成分のアドレス）を渡します。
  ///
  /// @return
  /// 交点が存在しない場合はnullptrを返します。\n
  /// 存在する場合はout_vectorを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecIntersectLineSphere
      ( type_ptr  out_vector
      , type_cptr in_center
      , T_Type    in_r
      , type_cptr in_ray_pos0
      , type_cptr in_ray_pos1
      )
  {
    const Vector& vc = *reinterpret_cast<const Vector*>(in_center);
    const Vector& v0 = *reinterpret_cast<const Vector*>(in_ray_pos0);
    const Vector& v1 = *reinterpret_cast<const Vector*>(in_ray_pos1);

    Vector m = v0 - vc;
    Vector d;
    GetVecNormalize( d, v1 - v0 );
    T_Type b = GetVecDot( m, d );
    T_Type c = GetVecDot( m, m ) - Squ(in_r);

    // ｒの原点がｓの外側にあり（ｃ＞０）、ｒがｓから離れていく方向を指している場合（ｂ＞０）に終了
    if( c > 0.0f  &&  b > 0.0f )
    {
      return nullptr;
    }
    T_Type discr = b * b - c;
    // 負の判別式は光線が球を外れていることに一致
    if( discr < 0.0f )
    {
      return nullptr;
    }
    // これで光線は球と交差していることがわかり、交差する最小の値ｔを計算
    T_Type t = -b - sqrtf( discr );
    // ｔが負である場合、光線は球の内側から開始しているのでｔをゼロにクランプ
    if( t < 0.0f )
    {
      t = 0.0f;
    }

    Vector& v = *reinterpret_cast<const Vector*>(out_vector);
    v = v1 + v0 * t;

    return out_vector;
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのマトリクス変換後のｘ値の取得
  /// 
  /// @param[in] in_vector : ３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_matrix : ４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return 変換後のベクトルｘを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecTransformX( type_cptr in_vector, type_cptr in_matrix )
  {
    return
      in_vector[0] * in_matrix[0] +
      in_vector[1] * in_matrix[4] +
      in_vector[2] * in_matrix[8] + in_matrix[12];
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのマトリクス変換後のｙ値を取得
  /// 
  /// @param[in] in_vector : ３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_matrix : ４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return 変換後のベクトルｙを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecTransformY( type_cptr in_vector, type_cptr in_matrix )
  {
    return in_vector[0]*in_matrix[1] + in_vector[1]*in_matrix[5] + in_vector[2]*in_matrix[9] + in_matrix[13];
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのマトリクス変換後のｚ値を取得
  ///
  /// @param[in] in_vector : ３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_matrix : ４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return 変換後のベクトルｚを返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static T_Type GetVecTransformZ( type_cptr in_vector, type_cptr in_matrix )
  {
    return in_vector[0]*in_matrix[2] + in_vector[1]*in_matrix[6] + in_vector[2]*in_matrix[10] + in_matrix[14];
  }



  // _____________________________________________________________________________
  /// @brief マトリクス変換後の３Ｄベクトルを取得
  ///
  /// @param[out] out_vector
  ///   : 変換後のベクトルを格納する３Ｄベクトル（先頭の成分のアドレス）を渡します。\n
  ///   : ※ in_vectorと同じアドレスを渡すと正しい値を返さないので注意してください。
  /// @param[in] in_vector
  ///   : 変換元の３Ｄベクトル（先頭の成分のアドレス）を指定します。\n
  ///   : ※ out_vectorと同じアドレスを渡すと正しい値を返さないので注意してください。
  /// @param[in] in_matrix
  ///   : 適用する４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetVecTransform
      ( type_ptr  out_vector
      , type_cptr in_vector
      , type_cptr in_matrix
      )
  {
    out_vector[0] = GetVecTransformX( in_vector, in_matrix );
    out_vector[1] = GetVecTransformY( in_vector, in_matrix );
    out_vector[2] = GetVecTransformZ( in_vector, in_matrix );
    return out_vector;
  }


  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのマトリクス変換
  ///
  /// @param[in,out] io_vector
  ///   : 変換する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 適用する４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr VecTransform( type_ptr io_vector, type_cptr in_matrix )
  {
    T_Type v[3] = { io_vector[0], io_vector[1], io_vector[2] };
    return GetVecTransform( io_vector, v, in_matrix );
  }



  // _____________________________________________________________________________
  /// @brief 単位マトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixIdentity( type_ptr out_matrix )
  {
    out_matrix[ 0] = 1; out_matrix[ 1] = 0; out_matrix[ 2] = 0; out_matrix[ 3] = 0;
    out_matrix[ 4] = 0; out_matrix[ 5] = 1; out_matrix[ 6] = 0; out_matrix[ 7] = 0;
    out_matrix[ 8] = 0; out_matrix[ 9] = 0; out_matrix[10] = 1; out_matrix[11] = 0;
    out_matrix[12] = 0; out_matrix[13] = 0; out_matrix[14] = 0; out_matrix[15] = 1;
    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief マトリクス同士の乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix1
  ///   : 計算元４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_matrix2
  ///   : 乗算する４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  ///
  /// @note 
  /// out_matrix = in_matrix1 * in_matrix2
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiply
      ( type_ptr  out_matrix
      , type_cptr in_matrix1
      , type_cptr in_matrix2
      )
  {
    // コード簡易化用（きっと最適化で削除されるはず）
    type_ptr  const m0 = out_matrix;
    type_cptr const m1 = in_matrix1;
    type_cptr const m2 = in_matrix2;

    m0[ 0] = m1[ 0]*m2[0] + m1[ 1]*m2[4] + m1[ 2]*m2[ 8] + m1[ 3]*m2[12];
    m0[ 1] = m1[ 0]*m2[1] + m1[ 1]*m2[5] + m1[ 2]*m2[ 9] + m1[ 3]*m2[13];
    m0[ 2] = m1[ 0]*m2[2] + m1[ 1]*m2[6] + m1[ 2]*m2[10] + m1[ 3]*m2[14];
    m0[ 3] = m1[ 0]*m2[3] + m1[ 1]*m2[7] + m1[ 2]*m2[11] + m1[ 3]*m2[15];
    m0[ 4] = m1[ 4]*m2[0] + m1[ 5]*m2[4] + m1[ 6]*m2[ 8] + m1[ 7]*m2[12];
    m0[ 5] = m1[ 4]*m2[1] + m1[ 5]*m2[5] + m1[ 6]*m2[ 9] + m1[ 7]*m2[13];
    m0[ 6] = m1[ 4]*m2[2] + m1[ 5]*m2[6] + m1[ 6]*m2[10] + m1[ 7]*m2[14];
    m0[ 7] = m1[ 4]*m2[3] + m1[ 5]*m2[7] + m1[ 6]*m2[11] + m1[ 7]*m2[15];
    m0[ 8] = m1[ 8]*m2[0] + m1[ 9]*m2[4] + m1[10]*m2[ 8] + m1[11]*m2[12];
    m0[ 9] = m1[ 8]*m2[1] + m1[ 9]*m2[5] + m1[10]*m2[ 9] + m1[11]*m2[13];
    m0[10] = m1[ 8]*m2[2] + m1[ 9]*m2[6] + m1[10]*m2[10] + m1[11]*m2[14];
    m0[11] = m1[ 8]*m2[3] + m1[ 9]*m2[7] + m1[10]*m2[11] + m1[11]*m2[15];
    m0[12] = m1[12]*m2[0] + m1[13]*m2[4] + m1[14]*m2[ 8] + m1[15]*m2[12];
    m0[13] = m1[12]*m2[1] + m1[13]*m2[5] + m1[14]*m2[ 9] + m1[15]*m2[13];
    m0[14] = m1[12]*m2[2] + m1[13]*m2[6] + m1[14]*m2[10] + m1[15]*m2[14];
    m0[15] = m1[12]*m2[3] + m1[13]*m2[7] + m1[14]*m2[11] + m1[15]*m2[15];
    return m0;
  }




  // _____________________________________________________________________________
  /// @brief マトリクスを乗算する
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 乗算する４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return なし。
  /// 
  /// @note
  /// io_matrix *= in_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiply( type_ptr io_matrix, type_cptr in_matrix )
  {
    T_Type m[16];
    MatrixCopy( m, io_matrix );
    GetMatrixMultiply( io_matrix, m, in_matrix );
  }




  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  /// 
  /// @return なし。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotX( type_ptr out_matrix, T_Type in_cos, T_Type in_sin )
  {
    out_matrix[ 0]=1; out_matrix[ 1]=      0; out_matrix[ 2]=     0; out_matrix[ 3]=0;
    out_matrix[ 4]=0; out_matrix[ 5]= in_cos; out_matrix[ 6]=in_sin; out_matrix[ 7]=0;
    out_matrix[ 8]=0; out_matrix[ 9]=-in_sin; out_matrix[10]=in_cos; out_matrix[11]=0;
    out_matrix[12]=0; out_matrix[13]=      0; out_matrix[14]=     0; out_matrix[15]=1;
    return out_matrix;
  }



  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを設定（degree仕様）
  /// 
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_X
  ///   : ｘ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotXdeg( type_ptr out_matrix, int in_rot_X )
  {
    return GetMatrixRotX( out_matrix, Cos(in_rot_X), Sin(in_rot_X) );
  }




  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを設定（radian仕様）
  /// 
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_X
  ///   : ｘ軸の角度をradian単位で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotXrad( type_ptr out_matrix, T_Type in_rot_X )
  {
    return GetMatrixRotX( out_matrix, cosf(in_rot_X), sinf(in_rot_X) );
  }




  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotX
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , T_Type    in_cos
      , T_Type    in_sin
      )
  {
    T_Type const msin = -in_sin;
    
    out_matrix[ 0] = in_matrix[0];
    out_matrix[ 1] = in_matrix[1] * in_cos  +  in_matrix[2] * msin;
    out_matrix[ 2] = in_matrix[1] * in_sin  +  in_matrix[2] * in_cos;
    out_matrix[ 3] = in_matrix[3];
    out_matrix[ 4] = in_matrix[4];
    out_matrix[ 5] = in_matrix[5] * in_cos  +  in_matrix[6] * msin;
    out_matrix[ 6] = in_matrix[5] * in_sin  +  in_matrix[6] * in_cos;
    out_matrix[ 7] = in_matrix[7];
    out_matrix[ 8] = in_matrix[8];
    out_matrix[ 9] = in_matrix[9] * in_cos  +  in_matrix[10] * msin;
    out_matrix[10] = in_matrix[9] * in_sin  +  in_matrix[10] * in_cos;
    out_matrix[11] = in_matrix[11];
    out_matrix[12] = in_matrix[12];
    out_matrix[13] = in_matrix[13] * in_cos  +  in_matrix[14] * msin;
    out_matrix[14] = in_matrix[13] * in_sin  +  in_matrix[14] * in_cos;
    out_matrix[15] = in_matrix[15];
    return out_matrix;
  }




  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_rot_X
  ///   : ｘ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotXdeg
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , int       in_rot_X
      )
  {
    return GetMatrixMultiplyRotX( out_matrix, in_matrix, Cos(in_rot_X), Sin(in_rot_X) );
  }




  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_X
  ///   : ｙ軸の角度をradian単位で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotXrad
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , T_Type    in_rot_X
      )
  {
    return GetMatrixMultiplyRotX( out_matrix, in_matrix, cosf(in_rot_X), sinf(in_rot_X) );
  }




  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを乗算。
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotX( type_ptr io_matrix, T_Type in_cos, T_Type in_sin )
  {
    T_Type const msin = -in_sin;
    T_Type const m01 = io_matrix[1];
    T_Type const m02 = io_matrix[2];
    T_Type const m11 = io_matrix[5];
    T_Type const m12 = io_matrix[6];
    T_Type const m21 = io_matrix[9];
    T_Type const m22 = io_matrix[10];
    T_Type const m31 = io_matrix[13];
    T_Type const m32 = io_matrix[14];
    
    io_matrix[ 1] = m01 * in_cos  +  m02 * msin;
    io_matrix[ 2] = m01 * in_sin  +  m02 * in_cos;
    io_matrix[ 5] = m11 * in_cos  +  m12 * msin;
    io_matrix[ 6] = m11 * in_sin  +  m12 * in_cos;
    io_matrix[ 9] = m21 * in_cos  +  m22 * msin;
    io_matrix[10] = m21 * in_sin  +  m22 * in_cos;
    io_matrix[13] = m31 * in_cos  +  m32 * msin;
    io_matrix[14] = m31 * in_sin  +  m32 * in_cos;
  }



  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in]     in_rot_X : 軸の角度をdegree単位（0 - 360）で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotXdeg( type_ptr io_matrix, int in_rot_X )
  {
    MatrixMultiplyRotX( io_matrix, Cos(in_rot_X), Sin(in_rot_X) );
  }




  // _____________________________________________________________________________
  /// @brief ｘ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in]     in_rot_X : 軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotXrad( type_ptr io_matrix, T_Type in_rot_X )
  {
    MatrixMultiplyRotX( io_matrix, cosf(in_rot_X), sinf(in_rot_X) );
  }




  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｘ回転変換
  ///
  /// @param[in,out] io_vector
  ///   : 変換する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotX( type_ptr io_vector, T_Type in_cos, T_Type in_sin )
  {
    T_Type m[16];
    GetMatrixRotX( m, in_cos, in_sin );
    VecTransform( io_vector, m );

    return io_vector;
  }




  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｘ回転変換
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する３Ｄベクトル（先頭の成分のアドレス）渡します。
  /// @param[in] in_rot_X
  ///   : ｘ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotXdeg( type_ptr out_vector, int in_rot_X )
  {
    return GetVecRotX( out_vector, Cos(in_rot_X), Sin(in_rot_X) );
  }




  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｘ回転変換
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する３Ｄベクトル（先頭の成分のアドレス）渡します。
  /// @param[in]  in_rot_X
  ///   : ｘ軸の角度をradian単位で指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotXrad( type_ptr out_vector, T_Type in_rot_X )
  {
    return GetVecRotX( out_vector, cosf(in_rot_X), sinf(in_rot_X) );
  }




  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotY( type_ptr out_matrix, T_Type in_cos, T_Type in_sin )
  {
    out_matrix[ 0]=in_cos; out_matrix[ 1]=0; out_matrix[ 2]=-in_sin; out_matrix[ 3]=0;
    out_matrix[ 4]=     0; out_matrix[ 5]=1; out_matrix[ 6]=      0; out_matrix[ 7]=0;
    out_matrix[ 8]=in_sin; out_matrix[ 9]=0; out_matrix[10]= in_cos; out_matrix[11]=0;
    out_matrix[12]=     0; out_matrix[13]=0; out_matrix[14]=      0; out_matrix[15]=1;

    return out_matrix;
  }



  
  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを設定（degree仕様）
  /// 
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Y
  ///   : ｙ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotYdeg( type_ptr out_matrix, int in_rot_Y )
  {
    return GetMatrixRotY( out_matrix, Cos(in_rot_Y), Sin(in_rot_Y) );
  }




  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを設定（radian仕様）
  /// 
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in]  in_rot_Y
  ///   : ｙ軸の角度を指定します。radian単位。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotYrad( type_ptr out_matrix, T_Type in_rot_Y )
  {
    return GetMatrixRotY( out_matrix, cosf(in_rot_Y), sinf(in_rot_Y) );
  }



  
  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotY
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , T_Type    in_cos
      , T_Type    in_sin
      )
  {
    T_Type msin = -in_sin;
    
    out_matrix[ 0] = in_matrix[0] * in_cos +  in_matrix[2] * in_sin;
    out_matrix[ 1] = in_matrix[1];
    out_matrix[ 2] = in_matrix[0] * msin    +  in_matrix[2] * in_cos;
    out_matrix[ 3] = in_matrix[3];
    out_matrix[ 4] = in_matrix[4] * in_cos +  in_matrix[6] * in_sin;
    out_matrix[ 5] = in_matrix[5];
    out_matrix[ 6] = in_matrix[4] * msin    +  in_matrix[6] * in_cos;
    out_matrix[ 7] = in_matrix[7];
    out_matrix[ 8] = in_matrix[8] * in_cos +  in_matrix[10] * in_sin;
    out_matrix[ 9] = in_matrix[9];
    out_matrix[10] = in_matrix[8] * msin    +  in_matrix[10] * in_cos;
    out_matrix[11] = in_matrix[11];
    out_matrix[12] = in_matrix[12] * in_cos +  in_matrix[14] * in_sin;
    out_matrix[13] = in_matrix[13];
    out_matrix[14] = in_matrix[12] * msin    +  in_matrix[14] * in_cos;
    out_matrix[15] = in_matrix[15];
    return out_matrix;
  }





  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを乗算したマトリクスの取得。
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_rot_Y
///   : ｙ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotYdeg
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , int       in_rot_Y
      )
  {
    return GetMatrixMultiplyRotY( out_matrix, in_matrix, Cos(in_rot_Y), Sin(in_rot_Y) );
  }




  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_rot_Y
  ///   : ｙ軸の角度をradian単位で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotYrad
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , T_Type    in_rot_Y
      )
  {
    return GetMatrixMultiplyRotY( out_matrix, in_matrix, cosf(in_rot_Y), sinf(in_rot_Y) );
  }



  
  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotY( type_ptr io_matrix, T_Type in_cos, T_Type in_sin )
  {
    T_Type const msin = -in_sin;
    T_Type const m00 = io_matrix[0];
    T_Type const m02 = io_matrix[2];
    T_Type const m10 = io_matrix[4];
    T_Type const m12 = io_matrix[6];
    T_Type const m20 = io_matrix[8];
    T_Type const m22 = io_matrix[10];
    T_Type const m30 = io_matrix[12];
    T_Type const m32 = io_matrix[14];

    io_matrix[ 0] = m00 * in_cos +  m02 * in_sin;
    io_matrix[ 2] = m00 * msin    +  m02 * in_cos;
    io_matrix[ 4] = m10 * in_cos +  m12 * in_sin;
    io_matrix[ 6] = m10 * msin    +  m12 * in_cos;
    io_matrix[ 8] = m20 * in_cos +  m22 * in_sin;
    io_matrix[10] = m20 * msin    +  m22 * in_cos;
    io_matrix[12] = m30 * in_cos +  m32 * in_sin;
    io_matrix[14] = m30 * msin    +  m32 * in_cos;
  }




  
  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Y
  ///   : ｙ軸の角度をdegree単位（0 - 360）指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotYdeg( type_ptr io_matrix, int in_rot_Y )
  {
    MatrixMultiplyRotY( io_matrix, Cos(in_rot_Y), Sin(in_rot_Y) );
  }



  
  // _____________________________________________________________________________
  /// @brief ｙ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Y
  ///   : ｙ軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotYrad( type_ptr io_matrix, T_Type in_rot_Y )
  {
    MatrixMultiplyRotY( io_matrix, cosf(in_rot_Y), sinf(in_rot_Y) );
  }



  
  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｙ回転変換
  ///
  /// @param[in,out] io_vector
  ///   : 変換する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotY( type_ptr io_vector, T_Type in_cos, T_Type in_sin )
  {
    T_Type m[16];
    GetMatrixRotY( m, in_cos, in_sin );
    VecTransform( io_vector, m );
    return io_vector;
  }


  
  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｙ回転変換
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する３Ｄベクトル（先頭の成分のアドレス）渡します。
  /// @param[in] in_rot_Y
  ///   : ｙ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotYdeg( type_ptr out_vector, int in_rot_Y )
  {
    return GetVecRotY( out_vector, Cos(in_rot_Y), Sin(in_rot_Y) );
  }



  
  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｙ回転変換
  ///
  /// @param[out] out_vector
  ///   : 計算結果を格納する３Ｄベクトル（先頭の成分のアドレス）渡します。
  /// @param[in] in_rot_Y
  ///   : ｙ軸の角度をradian単位で指定します。
  ///
  /// @return out_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotYrad( type_ptr out_vector, T_Type in_rot_Y )
  {
    return GetVecRotY( out_vector, cosf(in_rot_Y), sinf(in_rot_Y) );
  }



  
  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotZ( type_ptr out_matrix, T_Type in_cos, T_Type in_sin )
  {
    out_matrix[ 0]= in_cos; out_matrix[ 1]=in_sin; out_matrix[ 2]= 0; out_matrix[ 3]=0;
    out_matrix[ 4]=-in_sin; out_matrix[ 5]=in_cos; out_matrix[ 6]= 0; out_matrix[ 7]=0;
    out_matrix[ 8]=      0; out_matrix[ 9]=     0; out_matrix[10]= 1; out_matrix[11]=0;
    out_matrix[12]=      0; out_matrix[13]=     0; out_matrix[14]= 0; out_matrix[15]=1;
    return out_matrix;
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを設定（degree仕様）
  /// 
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : ｚ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotZdeg( type_ptr out_matrix, int in_rot_Z )
  {
    return GetMatrixRotZ( out_matrix, Cos(in_rot_Z), Sin(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを設定（radian仕様）
  /// 
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : ｚ軸の角度をradian単位で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixRotZrad( type_ptr out_matrix, T_Type in_rot_Z )
  {
    return GetMatrixRotZ( out_matrix, cosf(in_rot_Z), sinf(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotZ
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , T_Type    in_cos
      , T_Type    in_sin
      )
  {
    T_Type msin = -in_sin;

    out_matrix[ 0] = in_matrix[ 0]*in_cos + in_matrix[ 1]*msin;
    out_matrix[ 1] = in_matrix[ 0]*in_sin + in_matrix[ 1]*in_cos;
    out_matrix[ 2] = in_matrix[ 2];
    out_matrix[ 3] = in_matrix[ 3];
    out_matrix[ 4] = in_matrix[ 4]*in_cos + in_matrix[ 5]*msin;
    out_matrix[ 5] = in_matrix[ 4]*in_sin + in_matrix[ 5]*in_cos;
    out_matrix[ 6] = in_matrix[ 6];
    out_matrix[ 7] = in_matrix[ 7];
    out_matrix[ 8] = in_matrix[ 8]*in_cos + in_matrix[ 9]*msin;
    out_matrix[ 9] = in_matrix[ 8]*in_sin + in_matrix[ 9]*in_cos;
    out_matrix[10] = in_matrix[10];
    out_matrix[11] = in_matrix[11];
    out_matrix[12] = in_matrix[12]*in_cos + in_matrix[13]*msin;
    out_matrix[13] = in_matrix[12]*in_sin + in_matrix[13]*in_cos;
    out_matrix[14] = in_matrix[14];
    out_matrix[15] = in_matrix[15];
    return out_matrix;
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_rot_Z
  ///   : ｚ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotZdeg
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , int       in_rot_Z
      )
  {
    return GetMatrixMultiplyRotZ( out_matrix, in_matrix, Cos(in_rot_Z), Sin(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算したマトリクスの取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 計算元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_rot_Z
///   : ｚ軸の角度をradian単位で指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixMultiplyRotZrad
      ( type_ptr  out_matrix
      , type_cptr in_matrix
      , T_Type    in_rot_Z
      )
  {
    return GetMatrixMultiplyRotZ( out_matrix, in_matrix, cosf(in_rot_Z), sinf(in_rot_Z) );
  }



  
  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotZ( type_ptr io_matrix, T_Type in_cos, T_Type in_sin )
  {
    T_Type msin = -in_sin;

    T_Type m00 = io_matrix[0];
    T_Type m01 = io_matrix[1];
    T_Type m10 = io_matrix[4];
    T_Type m11 = io_matrix[5];
    T_Type m20 = io_matrix[8];
    T_Type m21 = io_matrix[9];
    T_Type m30 = io_matrix[12];
    T_Type m31 = io_matrix[13];

    io_matrix[ 0] = m00 * in_cos  +  m01 * msin;
    io_matrix[ 1] = m00 * in_sin  +  m01 * in_cos;
    io_matrix[ 4] = m10 * in_cos  +  m11 * msin;
    io_matrix[ 5] = m10 * in_sin  +  m11 * in_cos;
    io_matrix[ 8] = m20 * in_cos  +  m21 * msin;
    io_matrix[ 9] = m20 * in_sin  +  m21 * in_cos;
    io_matrix[12] = m30 * in_cos  +  m31 * msin;
    io_matrix[13] = m30 * in_sin  +  m31 * in_cos;
  }



  
  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : ｚ軸の角度をdegree単位（0 - 360）で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotZdeg( type_ptr io_matrix, int in_rot_Z )
  {
    MatrixMultiplyRotZ( io_matrix, Cos(in_rot_Z), Sin(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ｚ回転マトリクスを乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : ｚ軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixMultiplyRotZrad( type_ptr io_matrix, T_Type in_rot_Z )
  {
    MatrixMultiplyRotZ( io_matrix, cosf(in_rot_Z), sinf(in_rot_Z) );
  }



  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｚ回転変換
  ///
  /// @param[in,out] io_vector
  ///   : 変換する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_cos : 計算済みcos値を指定します。
  /// @param[in] in_sin : 計算済みsin値を指定します。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotZ( type_ptr io_vector, T_Type in_cos, T_Type in_sin )
  {
    T_Type m[16];
    GetMatrixRotZ( m, in_cos, in_sin );
    VecTransform( io_vector, m );
    return io_vector;
  }




  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｚ回転変換
  ///
  /// @param[in,out] io_vector
  ///   : 変換する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : ｚ軸の角度をdegree単位（0 - 360）で指定します。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotZdeg( type_ptr io_vector, int in_rot_Z )
  {
    return GetVecRotZ( io_vector, Cos(in_rot_Z), Sin(in_rot_Z) );
  }




  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルのｚ回転変換
  ///
  /// @param[in,out] io_vector
  ///   : 変換する３Ｄベクトル（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rot_Z
  ///   : ｚ軸の角度をradian単位で指定します。
  ///
  /// @return io_vector
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetVecRotZrad( type_ptr io_vector, T_Type in_rot_Z )
  {
    return GetVecRotZ( io_vector, cosf(in_rot_Z), sinf(in_rot_Z) );
  }




  /// @cond
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // ３軸回転マトリクス取得用汎用マクロ
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  #define MUL_MATRIX_ROT( mtx, func0, func1, func2, cos0, sin0, cos1, sin1, cos2, sin2 ) {\
    func0(mtx,cos0,sin0);\
    func1(mtx,cos1,sin1);\
    func2(mtx,cos2,sin2);\
  }
  /// @endcond


  // _____________________________________________________________________________
  /// @brief ｘｙｚ回転マトリクス取得（degree単位仕様）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_deg_X : ｘ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Y : ｙ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Z : ｚ軸の軸の角度をdegree単位（0 - 360）で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotXYZdeg
      ( type_ptr io_matrix
      , int      in_deg_X
      , int      in_deg_Y
      , int      in_deg_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotX
      , MatrixMultiplyRotY
      , MatrixMultiplyRotZ
      , Cos(in_deg_X)
      , Sin(in_deg_X)
      , Cos(in_deg_Y)
      , Sin(in_deg_Y)
      , Cos(in_deg_Z)
      , Sin(in_deg_Z)
      );
  }

  // _____________________________________________________________________________
  /// @brief ｘｙｚ回転マトリクス取得（radian単位仕様）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rad_X : ｘ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Y : ｙ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Z : ｚ軸の軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotXYZrad
      ( type_ptr io_matrix
      , T_Type   in_rad_X
      , T_Type   in_rad_Y
      , T_Type   in_rad_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotX
      , MatrixMultiplyRotY
      , MatrixMultiplyRotZ
      , cosf(in_rad_X)
      , sinf(in_rad_X)
      , cosf(in_rad_Y)
      , sinf(in_rad_Y)
      , cosf(in_rad_Z)
      , sinf(in_rad_Z)
      );
  }

  // _____________________________________________________________________________
  /// @brief ｘｚｙ回転マトリクス取得（degree単位仕様）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_deg_X : ｘ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Y : ｙ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Z : ｚ軸の軸の角度をdegree単位（0 - 360）で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotXZYdeg
      ( type_ptr io_matrix
      , int      in_deg_X
      , int      in_deg_Y
      , int      in_deg_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotX
      , MatrixMultiplyRotZ
      , MatrixMultiplyRotY
      , Cos(in_deg_X)
      , Sin(in_deg_Y)
      , Cos(in_deg_Z)
      , Sin(in_deg_Z)
      , Cos(in_deg_Y)
      , Sin(in_deg_Y)
      );
  }

  // _____________________________________________________________________________
  /// @brief ｘｚｙ回転マトリクス取得（radian単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rad_X : ｘ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Y : ｙ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Z : ｚ軸の軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotXZYrad
      ( type_ptr io_matrix
      , T_Type   in_rad_X
      , T_Type   in_rad_Y
      , T_Type   in_rad_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotX
      , MatrixMultiplyRotZ
      , MatrixMultiplyRotY
      , cosf(in_rad_X)
      , sinf(in_rad_X)
      , cosf(in_rad_Z)
      , sinf(in_rad_Z)
      , cosf(in_rad_Y)
      , sinf(in_rad_Y)
      );
  }

  // _____________________________________________________________________________
  /// @brief ｙｘｚ回転マトリクス取得（degree単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_deg_X : ｘ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Y : ｙ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Z : ｚ軸の軸の角度をdegree単位（0 - 360）で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotYXZdeg
      ( type_ptr io_matrix
      , int      in_deg_X
      , int      in_deg_Y
      , int      in_deg_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotY
      , MatrixMultiplyRotX
      , MatrixMultiplyRotZ
      , Cos(in_deg_Y)
      , Sin(in_deg_Y)
      , Cos(in_deg_X)
      , Sin(in_deg_X)
      , Cos(in_deg_Z)
      , Sin(in_deg_Z)
      );
  }

  // _____________________________________________________________________________
  /// @brief ｙｘｚ回転マトリクス取得（radian単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rad_X : ｘ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Y : ｙ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Z : ｚ軸の軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotYXZrad
      ( type_ptr io_matrix
      , T_Type   in_rad_X
      , T_Type   in_rad_Y
      , T_Type   in_rad_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotY
      , MatrixMultiplyRotX
      , MatrixMultiplyRotZ
      , cosf(in_rad_Y)
      , sinf(in_rad_Y)
      , cosf(in_rad_X)
      , sinf(in_rad_X)
      , cosf(in_rad_Z)
      , sinf(in_rad_Z)
      );
  }


  // _____________________________________________________________________________
  /// @brief ｙｚｘ回転マトリクス取得（degree単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_deg_X : ｘ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Y : ｙ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Z : ｚ軸の軸の角度をdegree単位（0 - 360）で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotYZXdeg
      ( type_ptr io_matrix
      , int      in_deg_X
      , int      in_deg_Y
      , int      in_deg_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotY
      , MatrixMultiplyRotZ
      , MatrixMultiplyRotX
      , Cos(in_deg_Y)
      , Sin(in_deg_Y)
      , Cos(in_deg_Z)
      , Sin(in_deg_Z)
      , Cos(in_deg_X)
      , Sin(in_deg_X)
      );
  }

  // _____________________________________________________________________________
  /// @brief ｙｚｘ回転マトリクス取得（radian単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rad_X : ｘ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Y : ｙ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Z : ｚ軸の軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotYZXrad
      ( type_ptr io_matrix
      , T_Type   in_rad_X
      , T_Type   in_rad_Y
      , T_Type   in_rad_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotY
      , MatrixMultiplyRotZ
      , MatrixMultiplyRotX
      , cosf(in_rad_Y)
      , sinf(in_rad_Y)
      , cosf(in_rad_Z)
      , sinf(in_rad_Z)
      , cosf(in_rad_X)
      , sinf(in_rad_X)
      );
  }


  // _____________________________________________________________________________
  /// @brief ｚｘｙ回転マトリクス取得（degree単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_deg_X : ｘ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Y : ｙ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Z : ｚ軸の軸の角度をdegree単位（0 - 360）で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotZXYdeg
      ( type_ptr io_matrix
      , int      in_deg_X
      , int      in_deg_Y
      , int      in_deg_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotZ
      , MatrixMultiplyRotX
      , MatrixMultiplyRotY
      , Cos(in_deg_Z)
      , Sin(in_deg_Z)
      , Cos(in_deg_X)
      , Sin(in_deg_X)
      , Cos(in_deg_Y)
      , Sin(in_deg_Y)
      );
  }
  
  // _____________________________________________________________________________
  /// @brief ｚｘｙ回転マトリクス取得（radian単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rad_X : ｘ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Y : ｙ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Z : ｚ軸の軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotZXYrad
      ( type_ptr io_matrix
      , T_Type   in_rad_X
      , T_Type   in_rad_Y
      , T_Type   in_rad_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotZ
      , MatrixMultiplyRotX
      , MatrixMultiplyRotY
      , cosf(in_rad_Z)
      , sinf(in_rad_Z)
      , cosf(in_rad_X)
      , sinf(in_rad_X)
      , cosf(in_rad_Y)
      , sinf(in_rad_Y)
      );
  }


  // _____________________________________________________________________________
  /// @brief ｚｙｘ回転マトリクス取得（degree単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_deg_X : ｘ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Y : ｙ軸の軸の角度をdegree単位（0 - 360）で指定します。
  /// @param[in] in_deg_Z : ｚ軸の軸の角度をdegree単位（0 - 360）で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotZYXdeg
      ( type_ptr io_matrix
      , int      in_deg_X
      , int      in_deg_Y
      , int      in_deg_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotZ
      , MatrixMultiplyRotY
      , MatrixMultiplyRotX
      , Cos(in_deg_Z)
      , Sin(in_deg_Z)
      , Cos(in_deg_Y)
      , Sin(in_deg_Y)
      , Cos(in_deg_X)
      , Sin(in_deg_X)
      );
  }
  
  // _____________________________________________________________________________
  /// @brief ｚｙｘ回転マトリクス取得（radian単位）
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_rad_X : ｘ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Y : ｙ軸の軸の角度をradian単位で指定します。
  /// @param[in] in_rad_Z : ｚ軸の軸の角度をradian単位で指定します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixMultiplyRotZYXrad
      ( type_ptr io_matrix
      , T_Type   in_rad_X
      , T_Type   in_rad_Y
      , T_Type   in_rad_Z
      )
  {
    MUL_MATRIX_ROT
      ( io_matrix
      , MatrixMultiplyRotZ
      , MatrixMultiplyRotY
      , MatrixMultiplyRotX
      , cosf(in_rad_Z)
      , sinf(in_rad_Z)
      , cosf(in_rad_Y)
      , sinf(in_rad_Y)
      , cosf(in_rad_X)
      , sinf(in_rad_X)
      );
  }




  // _____________________________________________________________________________
  /// @brief 平行移動マトリクスを設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_move_xyz
  ///   : 移動量表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixTranslate( type_ptr out_matrix, type_cptr in_move_xyz )
  {
    // コード簡易化用（最適化で削除される？）
    const float x = in_move_xyz[0];
    const float y = in_move_xyz[1];
    const float z = in_move_xyz[2];
    // 設定
    out_matrix[ 0]=1; out_matrix[ 1]=0; out_matrix[ 2]=0; out_matrix[ 3]=0;
    out_matrix[ 4]=0; out_matrix[ 5]=1; out_matrix[ 6]=0; out_matrix[ 7]=0;
    out_matrix[ 8]=0; out_matrix[ 9]=0; out_matrix[10]=1; out_matrix[11]=0;
    out_matrix[12]=x; out_matrix[13]=y; out_matrix[14]=z; out_matrix[15]=1;
    return out_matrix;
  }




  // _____________________________________________________________________________
  /// @brief マトリクスの平行移動処理
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_move_xyz
  ///   : 移動量表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return io_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void MatrixTranslate( type_ptr io_matrix, type_cptr in_move_xyz )
  {
    io_matrix[12] += in_move_xyz[0];
    io_matrix[13] += in_move_xyz[1];
    io_matrix[14] += in_move_xyz[2];
  }




  // _____________________________________________________________________________
  /// @brief マトリクスの平行移動処理
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_move_x : ｘ移動量を指定します。
  /// @param[in] in_move_y : ｙ移動量を指定します。
  /// @param[in] in_move_z : ｚ移動量を指定します。
  ///
  /// @return io_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    MatrixTranslate
      ( type_ptr io_matrix
      , T_Type   in_move_x
      , T_Type   in_move_y
      , T_Type   in_move_z
      )
  {
    io_matrix[12] += in_move_x;
    io_matrix[13] += in_move_y;
    io_matrix[14] += in_move_z;
  }




  // _____________________________________________________________________________
  /// @brief スケール行列の設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_scale_xyz
  ///   : 倍率を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixScaling( type_ptr out_matrix, type_cptr in_scale_xyz )
  {
    // コード簡易化用（最適化で削除される？）
    const type_ptr m = out_matrix;
    const float    x = in_scale_xyz[0];
    const float    y = in_scale_xyz[1];
    const float    z = in_scale_xyz[2];
    // 設定
    m[ 0]= x; m[ 1]= 0; m[ 2]= 0; m[ 3]=0;
    m[ 4]= 0; m[ 5]= y; m[ 6]= 0; m[ 7]=0;
    m[ 8]= 0; m[ 9]= 0; m[10]= z; m[11]=0;
    m[12]= 0; m[13]= 0; m[14]= 0; m[15]=1;

    return out_matrix;
  }



  // _____________________________________________________________________________
  /// @brief スケール行列の設定
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_scale_x : ｘ方向の倍率を指定します。
  /// @param[in] in_scale_y : ｙ方向の倍率を指定します。
  /// @param[in] in_scale_z : ｚ方向の倍率を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixScaling
      ( type_ptr out_matrix
      , T_Type   in_scale_x
      , T_Type   in_scale_y
      , T_Type   in_scale_z
      )
  {
    // コード簡易化用（最適化で削除される？）
    const type_ptr m = out_matrix;
    const float    x = in_scale_x;
    const float    y = in_scale_y;
    const float    z = in_scale_z;
    // 設定
    m[ 0]= x; m[ 1]= 0; m[ 2]= 0; m[ 3]=0;
    m[ 4]= 0; m[ 5]= y; m[ 6]= 0; m[ 7]=0;
    m[ 8]= 0; m[ 9]= 0; m[10]= z; m[11]=0;
    m[12]= 0; m[13]= 0; m[14]= 0; m[15]=1;

    return out_matrix;
  }



  // _____________________________________________________________________________
  /// @brief スケール行列の乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_scale_xyz
  ///   : 倍率を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return io_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr MatrixMultiplyScaling( type_ptr io_matrix, type_cptr in_scale_xyz )
  {
    // コード簡易化用（最適化で削除される？）
    const type_ptr m = io_matrix;
    const float    x = in_scale_xyz[0];
    const float    y = in_scale_xyz[1];
    const float    z = in_scale_xyz[2];
    // 設定
    m[ 0] *= x; m[ 1] *= y; m[ 2] *= z;
    m[ 4] *= x; m[ 5] *= y; m[ 6] *= z;
    m[ 8] *= x; m[ 9] *= y; m[10] *= z;
    m[12] *= x; m[13] *= y; m[14] *= z;

    return io_matrix;
  }



  // _____________________________________________________________________________
  /// @brief スケール行列の乗算
  ///
  /// @param[in,out] io_matrix
  ///   : 変換する４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_scale_x : ｘ方向の倍率を指定します。
  /// @param[in] in_scale_y : ｙ方向の倍率を指定します。
  /// @param[in] in_scale_z : ｚ方向の倍率を指定します。
  ///
  /// @return io_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    MatrixMultiplyScaling
      ( type_ptr io_matrix
      , T_Type   in_scale_x
      , T_Type   in_scale_y
      , T_Type   in_scale_z
      )
  {
    // コード簡易化用（最適化で削除される？）
    const type_ptr m = io_matrix;
    const float    x = in_scale_x;
    const float    y = in_scale_y;
    const float    z = in_scale_z;
    // 設定
    m[ 0] *= x; m[ 1] *= y; m[ 2] *= z;
    m[ 4] *= x; m[ 5] *= y; m[ 6] *= z;
    m[ 8] *= x; m[ 9] *= y; m[10] *= z;
    m[12] *= x; m[13] *= y; m[14] *= z;

    return io_matrix;
  }





  // _____________________________________________________________________________
  /// @brief 逆行列の取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 変換元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return
  /// 変換できた場合はout_matrixを返す。\n
  /// 失敗(0による除算等)した場合、nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixInverse( type_ptr out_matrix, type_cptr in_matrix )
  {
    Matrix& out_ = *(Matrix*)out_matrix;
    Matrix  in_  = *(Matrix*)in_matrix; // out_matrix == in_matrixでも計算できるようコピー

    T_Type tmp; //一時的なデータを蓄える
    int i, j, k; //カウンタ
    int n = 4;  //配列の次数
    // 単位行列を設定
    GetMatrixIdentity( out_ );
    //掃き出し法
    for( i = 0; i < n; i++ )
    {
      tmp = in_(i,i);
      if( tmp == 0 )
      {
        return nullptr;
      }
      tmp = 1.0f / tmp;
      for( j = 0; j < n; j++ )
      {
        in_(i,j) *= tmp;
        out_(i,j) *= tmp;
      }
      for( j = 0; j < n; j++ )
      {
        if( i != j )
        {
          tmp = in_(j,i);
          for( k = 0; k < n; k++ )
          {
            in_(j,k) -= in_(i,k) * tmp;
            out_(j,k) -= out_(i,k) * tmp;
          }
        }
      }
    }

    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief 転置行列の取得
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 変換元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixTranspose( type_ptr out_matrix, type_cptr in_matrix )
  {
    out_matrix[ 0] = in_matrix[ 0];
    out_matrix[ 1] = in_matrix[ 4];
    out_matrix[ 2] = in_matrix[ 8];
    out_matrix[ 3] = in_matrix[12];
    out_matrix[ 4] = in_matrix[ 1];
    out_matrix[ 5] = in_matrix[ 5];
    out_matrix[ 6] = in_matrix[ 9];
    out_matrix[ 7] = in_matrix[13];
    out_matrix[ 8] = in_matrix[ 2];
    out_matrix[ 9] = in_matrix[ 6];
    out_matrix[10] = in_matrix[10];
    out_matrix[11] = in_matrix[14];
    out_matrix[12] = in_matrix[ 3];
    out_matrix[13] = in_matrix[ 7];
    out_matrix[14] = in_matrix[11];
    out_matrix[15] = in_matrix[15];

    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief 平行移動行列の抽出
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 変換元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixExtractTranslate( type_ptr out_matrix, type_cptr in_matrix )
  {
    out_matrix[ 0] = 1.0f;
    out_matrix[ 1] = 0.0f;
    out_matrix[ 2] = 0.0f;
    out_matrix[ 3] = 0.0f;
    out_matrix[ 4] = 0.0f;
    out_matrix[ 5] = 1.0f;
    out_matrix[ 6] = 0.0f;
    out_matrix[ 7] = 0.0f;
    out_matrix[ 8] = 0.0f;
    out_matrix[ 9] = 0.0f;
    out_matrix[10] = 1.0f;
    out_matrix[11] = 0.0f;
    out_matrix[12] = in_matrix[12];
    out_matrix[13] = in_matrix[13];
    out_matrix[14] = in_matrix[14];
    out_matrix[15] = 1.0f;

    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief 回転行列の抽出
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 変換元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixExtractRotate( type_ptr out_matrix, type_cptr in_matrix )
  {
    out_matrix[ 0] = in_matrix[0];
    out_matrix[ 1] = in_matrix[1];
    out_matrix[ 2] = in_matrix[2];
    out_matrix[ 3] = 0.0f;
    out_matrix[ 4] = in_matrix[4];
    out_matrix[ 5] = in_matrix[5];
    out_matrix[ 6] = in_matrix[6];
    out_matrix[ 7] = 0.0f;
    out_matrix[ 8] = in_matrix[8];
    out_matrix[ 9] = in_matrix[9];
    out_matrix[10] = in_matrix[10];
    out_matrix[11] = 0.0f;
    out_matrix[12] = 0.0f;
    out_matrix[13] = 0.0f;
    out_matrix[14] = 0.0f;
    out_matrix[15] = 1.0f;

    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief スケーリング行列の抽出
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 変換元の４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr GetMatrixExtractScale( type_ptr out_matrix, type_cptr in_matrix )
  {
    out_matrix[ 0] = in_matrix[0];
    out_matrix[ 1] = 0.0f;
    out_matrix[ 2] = 0.0f;
    out_matrix[ 3] = 0.0f;
    out_matrix[ 4] = 0.0f;
    out_matrix[ 5] = in_matrix[5];
    out_matrix[ 6] = 0.0f;
    out_matrix[ 7] = 0.0f;
    out_matrix[ 8] = 0.0f;
    out_matrix[ 9] = 0.0f;
    out_matrix[10] = in_matrix[10];
    out_matrix[11] = 0.0f;
    out_matrix[12] = 0.0f;
    out_matrix[13] = 0.0f;
    out_matrix[14] = 0.0f;
    out_matrix[15] = 1.0f;

    return out_matrix;
  }



  // _____________________________________________________________________________
  /// @brief YXZ回転行列から各軸周りの角度をradian単位で取得
  ///
  /// @param[in] in_matrix
  ///   : YXZ回転行列が格納された４ｘ４マトリクス。
  /// @param[out] out_sin_tbl
  ///   : sin値を格納するためのT_Type[3]へのテーブルポインタ。
  /// @param[out] out_cos_tbl
  ///   : cos値を格納するためのT_Type[3]へのテーブルポインタ。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    GetMatrixAnalysisRotate
      ( type_ptr in_matrix
      , T_Type   out_sin_tbl[3]
      , T_Type   out_cos_tbl[3]
      )
  {
    T_Type& sx = out_sin_tbl[0];
    T_Type& sy = out_sin_tbl[1];
    T_Type& sz = out_sin_tbl[2];
    T_Type& cx = out_cos_tbl[0];
    T_Type& cy = out_cos_tbl[1];
    T_Type& cz = out_cos_tbl[2];
    Matrix& m = *((Matrix*)in_matrix);

    sx = m(2,1);
    cx = ::sqrtf(1.0f - Squ(sx));
    if( cx == 0.0f ) // rx==90度
    {}
    else
    {
      sy = m(2,0) / -cx;
      cy = m(2,2) / cx;
      sz = m(0,1) / -cx;
      cz = m(1,1) / cx;

      if( Abs(m(0,0) - cy*cz-sy*sx*sz) > 0.03125f )
      {
        cx = -cx;
        sy = m(2,0) / -cx;
        cy = m(2,2) / cx;
        sz = m(0,1) / -cx;
        cz = m(1,1) / cx;
      }
    }
  }







  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルテーブルの加算
  ///
  /// @param[in,out] io_xyz_table
  ///   : 変換するベクトル配列（先頭の３Ｄベクトルの先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector_add
  ///   : 加算する３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_size
  ///   : 次のベクトルへのバイトオフセット（構造体サイズ）を指定します\n
  ///   : ※ sizeof(io_xyz_table[0])byteでアライメントされます。
  /// @param[in] in_num
  ///   : 配列の要素数を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    VecAddTable
      ( type_ptr  io_xyz_table
      , type_cptr in_vector_add
      , long      in_size
      , long      in_num
      )
  {
    PRIVATE_CALL_TABLE_ARG2_( io_xyz_table, in_vector_add, in_size, in_num, VecAdd );
  }



  
  // _____________________________________________________________________________
  /// @brief ３Ｄベクトルテーブルの減算
  ///
  /// @param[in,out] io_xyz_table
  ///   : 変換するベクトル配列（先頭の３Ｄベクトルの先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector_sub
  ///   : 減算する３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_size
  ///   : 次のベクトルへのバイトオフセット（構造体サイズ）を指定します。\n
  ///   : ※ sizeof(io_xyz_table[0])byteでアライメントされます。
  /// @param[in] in_num
  ///   : 配列の要素数を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    VecSubTable
      ( type_ptr  io_xyz_table
      , type_cptr in_vector_sub
      , long      in_size
      , long      in_num
      )
  {
    PRIVATE_CALL_TABLE_ARG2_( io_xyz_table, in_vector_sub, in_size, in_num, VecSub );
  }




  // _____________________________________________________________________________
  /// @brief マトリクス変換後の３Ｄベクトルの取得（配列指定仕様）
  ///
  /// @param[in,out] io_xyz_table
  ///   : 変換する３Ｄベクトル配列（先頭の３Ｄベクトルの先頭の成分のアドレス）を渡します。
  /// @param[in] in_matrix
  ///   : 適用する４ｘ４マトリクス（先頭の成分のアドレス）を指定します。
  /// @param[in] in_size
  ///   : 次のベクトルへのバイトオフセット（構造体サイズ）を指定します。\n
  ///   : ※ sizeof(io_xyz_table[0])byteでアライメントされます。
  /// @param[in] in_num
  ///   : 配列の要素数を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static void
    VecTransformTable
      ( type_ptr  io_xyz_table
      , type_cptr in_matrix
      , long      in_size
      , long      in_num
      )
  {
    PRIVATE_CALL_TABLE_ARG2_( io_xyz_table, in_matrix, in_size, in_num, GetVecTransform );
  }



  // _____________________________________________________________________________
  /// @brief 四辺形の凸判定。
  ///
  /// @param[in] in_vectorA : １番目の頂点を指す３Ｄベクトル（先頭の成分のアドレス）
  /// @param[in] in_vectorB : ２番目の頂点を指す３Ｄベクトル（先頭の成分のアドレス）
  /// @param[in] in_vectorC : ３番目の頂点を指す３Ｄベクトル（先頭の成分のアドレス）
  /// @param[in] in_vectorD : ４番目の頂点を指す３Ｄベクトル（先頭の成分のアドレス）
  ///
  /// @return 凸ならtrueを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static int
    IsConvexQuad
      ( type_cptr in_vectorA
      , type_cptr in_vectorB
      , type_cptr in_vectorC
      , type_cptr in_vectorD
      )
  {
    const Vector& a = *reinterpret_cast<const Vector*>(in_vectorA);
    const Vector& b = *reinterpret_cast<const Vector*>(in_vectorB);
    const Vector& c = *reinterpret_cast<const Vector*>(in_vectorC);
    const Vector& d = *reinterpret_cast<const Vector*>(in_vectorD);
    // 
    Vector bda, bdc;
    GetVecCross( bda, d - b, a - b );
    GetVecCross( bdc, d - b, c - b );
    if( GetVecDot( bda, bdc ) >= 0.0f ){ return false; }

    //
    Vector acd, acb;
    GetVecCross( acd, c - a, d - a );
    GetVecCross( acb, c - a, b - a );
    return GetVecDot( acd, acb ) < 0.0f;
  }


  // _____________________________________________________________________________
  /// @brief ビュー行列の取得（左手系）
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector_eye
  ///   : カメラの位置を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector_at
  ///   : 注視点の位置を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector_up
  ///   : カメラの上方を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixLookAtLH
      ( type_ptr  out_matrix
      , type_cptr in_vector_eye
      , type_cptr in_vector_at
      , type_cptr in_vector_up
      )
  {
    Vector x, y, z;
    // ビュー座標のｚ軸を求める。
    VecNormalize( GetVecSub( z, in_vector_at, in_vector_eye ) );
    // ビュー座標のｘ軸を求める。
    VecNormalize( GetVecCross( x, z, in_vector_up ) ); // GetVecCross( x, in_vector_up, z )では無いと思うのだが…
    // ビュー座標のｙ軸を求める。
    GetVecCross( y, x, z );

    //
    out_matrix[ 0] = x.x;
    out_matrix[ 1] = y.x;
    out_matrix[ 2] = z.x;
    out_matrix[ 3] = 0;
    out_matrix[ 4] = x.y;
    out_matrix[ 5] = y.y;
    out_matrix[ 6] = z.y;
    out_matrix[ 7] = 0;
    out_matrix[ 8] = x.z;
    out_matrix[ 9] = y.z;
    out_matrix[10] = z.z;
    out_matrix[11] = 0;
    out_matrix[12] = -GetVecDot( x, in_vector_eye );
    out_matrix[13] = -GetVecDot( y, in_vector_eye );
    out_matrix[14] = -GetVecDot( z, in_vector_eye );
    out_matrix[15] = 1;

    return out_matrix;
  }

  // _____________________________________________________________________________
  /// @brief ビュー行列の取得（右手系）
  ///
  /// @param[out] out_matrix
  ///   : 取得用の４ｘ４マトリクス（先頭の成分のアドレス）を渡します。
  /// @param[in] in_vector_eye
  ///   : カメラの位置を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector_at
  ///   : 注視点の位置を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  /// @param[in] in_vector_up
  ///   : カメラの上方を表す３Ｄベクトル（先頭の成分のアドレス）を指定します。
  ///
  /// @return out_matrix
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  static type_ptr
    GetMatrixLookAtRH
      ( type_ptr  out_matrix
      , type_cptr in_vector_eye
      , type_cptr in_vector_at
      , type_cptr in_vector_up
      )
  {
    Vector x, y, z;
    // ビュー座標のｚ軸を求める。
    VecNormalize( GetVecSub( z, in_vector_eye, in_vector_at ) );
    // ビュー座標のｘ軸を求める。
    VecNormalize( GetVecCross( x, in_vector_up, z ) );
    // ビュー座標のｙ軸を求める。
    GetVecCross( y, z, x );

    //
    out_matrix[ 0] = x.x;
    out_matrix[ 1] = y.x;
    out_matrix[ 2] = z.x;
    out_matrix[ 3] = 0;
    out_matrix[ 4] = x.y;
    out_matrix[ 5] = y.y;
    out_matrix[ 6] = z.y;
    out_matrix[ 7] = 0;
    out_matrix[ 8] = x.z;
    out_matrix[ 9] = y.z;
    out_matrix[10] = z.z;
    out_matrix[11] = 0;
    out_matrix[12] = -GetVecDot( x, in_vector_eye );
    out_matrix[13] = -GetVecDot( y, in_vector_eye );
    out_matrix[14] = -GetVecDot( z, in_vector_eye );
    out_matrix[15] = 1;

    return out_matrix;
  }


  // _____________________________________________________________________________
  /// @brief マトリクスクラス
  ///
  // *****************************************************************************
  class Matrix_
    : public CPL::Core::zzz_::Vector_< T_Type, 16, Matrix_ >
  {
  protected:
    // 使用禁止(ValuseSetで定義されているため)
    template<class T0> Matrix_  operator / ( const T0& d )       { return Matrix_(); }
    template<class T0> Matrix_  operator / ( const T0& d ) const { return Matrix_(); }
    template<class T0> void  operator /= ( const T0& d ){ _Division( d ); }

  public:
      union {
          struct {
              T_Type  _11, _12, _13, _14;
              T_Type  _21, _22, _23, _24;
              T_Type  _31, _32, _33, _34;
              T_Type  _41, _42, _43, _44;
          };
          T_Type m[4][4];
      };

    operator type_ptr()        { return &m[0][0]; }
    operator type_cptr() const { return &m[0][0]; }

    T_Type& operator ()( int row, int col )       { return m[ row ][ col ]; }
    T_Type  operator ()( int row, int col ) const { return m[ row ][ col ]; }

    Matrix_& operator =( _in<Matrix_> mtx )
    {
      MatrixCopy( m[0], mtx );
      return *this;
    }

    Matrix_& operator *= ( type_cptr      in_matrix   ){ MatrixMultiply( *this, in_matrix ); return *this; }
    Matrix_& operator *= ( Matrix_ const& in_matrix   ){ return (*this *= (type_cptr)in_matrix); }
    Matrix_& operator *= ( T_Type         in_value ){ for(int i=0;i<16;++i){this->get(i)*=in_value;} return *this; }
    Matrix_  operator *  ( type_cptr      in_matrix   ) const { return Matrix_(*this) *= in_matrix; }
    Matrix_  operator *  ( Matrix_ const& in_matrix   ) const { return Matrix_(*this) *= in_matrix; }
    Matrix_  operator *  ( T_Type         in_value ) const { return Matrix_(*this) *= in_value; }

    void    Identity(){ GetMatrixIdentity( *this ); } // Matrix_クラス 初期化
    Matrix_& Mul( type_cptr mtx ){ return *this *= mtx; } // マトリクス乗算
    Matrix_& Mul( const Matrix_& mtx ){ return *this *= mtx; } // マトリクス乗算
    Matrix_& RotXdeg( int    rx ){ MatrixMultiplyRotXdeg( *this, rx ); return *this; } // degree単位でｘ回転
    Matrix_& RotXrad( T_Type rx ){ MatrixMultiplyRotXrad( *this, rx ); return *this; } // radian単位でｘ回転
    Matrix_& RotYdeg( int    ry ){ MatrixMultiplyRotYdeg( *this, ry ); return *this; } // degree単位でｙ回転
    Matrix_& RotYrad( T_Type ry ){ MatrixMultiplyRotYrad( *this, ry ); return *this; } // radian単位でｙ回転
    Matrix_& RotZdeg( int    rz ){ MatrixMultiplyRotZdeg( *this, rz ); return *this; } // degree単位でｚ回転
    Matrix_& RotZrad( T_Type rz ){ MatrixMultiplyRotZrad( *this, rz ); return *this; } // radian単位でｚ回転
    Matrix_& Translate( T_Type mx, T_Type my, T_Type mz ){ MatrixTranslate( *this, mx, my, mz ); return *this; } // 移動
    Matrix_& Translate( type_cptr xyz )                  { MatrixTranslate( *this, xyz ); return *this; } // 移動
    Matrix_& Scaling( T_Type sx, T_Type sy, T_Type sz ){ MatrixMultiplyScaling( *this, sx, sy, sz ); return *this; } // スケーリング
    Matrix_& Scaling( type_cptr sc )                   { MatrixMultiplyScaling( *this, sc ); return *this; } // スケーリング

    Matrix_(){}
    Matrix_( Initialize_ ){ Identity(); }
    Matrix_( type_cptr p ){ MatrixCopy( *this, p ); }
    Matrix_( const Matrix_& mtx ){ MatrixCopy( *this, mtx ); }
    
    //typedef Matrix_*        ptr;
    //typedef Matrix_ const* cptr;
    //typedef Matrix_&        ref;
    //typedef Matrix_ const& cref;
  };

  typedef Matrix_ Matrix;


  // _____________________________________________________________________________
  /// @brief ３Ｄ系 バウンディングボックス
  ///
  // *****************************************************************************
  class BBox {
    Vector m_min;
    Vector m_max;

  public:
    void SetMax( const Vector& xyz )   { m_max = xyz; }
    void SetMax( T_Type x, T_Type y, T_Type z ){ m_max = Vector(x,y,z); }
    void SetMin( const Vector& xyz )   { m_min = xyz; }
    void SetMin( T_Type x, T_Type y, T_Type z ){ m_min = Vector(x,y,z); }

    const Vector* GetMin() const { return &m_min; }
    const Vector* GetMax() const { return &m_max; }

    bool Hit( const Vector& xyz ) const
    {
      if( m_min.x <= xyz.x  &&  xyz.x <= m_max.x  &&
          m_min.y <= xyz.y  &&  xyz.y <= m_max.y  &&
          m_min.z <= xyz.z  &&  xyz.z <= m_max.z )
      {
        return true;
      }
      return false;
    }
    bool Hit( T_Type x, T_Type y, T_Type z ) const { return Hit(Vector(x,y,z)); }
    bool Hit( BBox& box ) const {
      return (Hit(box.m_min) | Hit(box.m_max));
    }

    BBox& operator = ( BBox const& in_bbox )
    {
      m_min = *in_bbox.GetMin();
      m_max = *in_bbox.GetMax();

      return *this;
    }

    BBox() {}
    BBox( const Vector& in_vector_min, const Vector& in_vector_max )
      : m_min(in_vector_min), m_max(in_vector_max) {}
    BBox( const BBox& in_bbox )
    {
      *this = in_bbox;
    }
  };


}; // class D3


} // namespace Math
} // namespace CPL
