/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2009/X/X - 2016/12/23
/// 
/// @brief  メッシュ アニメーション関連
/// 
/// ****************************************************************************

#include "CPL_CDI_MeshData.h"

namespace CPL {
namespace CDI {


// _____________________________________________________________________________
/// @brief AnmData デフォルトコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::AnmData::AnmData()
  : m_user_ID( 0 )
  , m_play_index( 0 )
  , m_wait_frame( 0 )
{}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::AnmData::AnmData( cref<AnmData> in_data )
  : td_base( in_data )
{
  m_user_ID    = in_data.GetUserID();
  m_play_index = in_data.GetPlayIndex();
  m_wait_frame = 0;
  if( in_data.GetKeyListRoot() )
  {
    auto sp_new_data  = in_data.GetKeyListRoot()->CreateClone();
    m_sp_keylist_root = std::dynamic_pointer_cast<AnmKeyList>(sp_new_data);
  }
}


// _____________________________________________________________________________
/// @brief AnmData ムーブコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::AnmData::AnmData( rvref<AnmData> in_data )
  : td_base( std::move(in_data) )
{
  m_user_ID    = in_data.GetUserID();
  m_play_index = in_data.GetPlayIndex();
  m_wait_frame = 0;
  m_sp_keylist_root = std::move(in_data.m_sp_keylist_root);
}


// _____________________________________________________________________________
/// @copydoc doxycomment::func_zzf_setupData_by_File_
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::AnmData::zzf_setupData_by_File_
    ( pin<MeshFileInfo::Chunk> in_ptr_chunk
    , rio<Array_DataSPtr     > io_table_for_data_pointer
    , rio<Array_ChunkPtr     > io_table_for_chunk_pointer
    )
{
  char_cptr ptr_data_addr =
    reinterpret_cast<char_cptr>(in_ptr_chunk);
  char_cptr ptr_end_addr  =
    ptr_data_addr + in_ptr_chunk->m_size;
  MFI_AnimeData const* ptr_info_anime_data =
    reinterpret_cast<MFI_AnimeData const*>(ptr_data_addr);
  this->SetName( ptr_info_anime_data->m_name );

  // データポインタ登録
  io_table_for_data_pointer.Add
    ( ptr_info_anime_data->m_GID
    , this->GetLinkMyself()
    );
  // チャンクポインタ登録
  io_table_for_chunk_pointer.Add( this, in_ptr_chunk );

  // プライベートデータ設定
  //U32 keylist_num = ptr_info_anime_data->m_keylist_num;
  m_user_ID = ptr_info_anime_data->m_UID;

  // アドレス調整
  ptr_data_addr = reinterpret_cast<char_cptr>(ptr_info_anime_data + 1);

  // チャンクループ
  while( ptr_data_addr < ptr_end_addr )
  {
    auto* ptr_chunk =
      reinterpret_cast<MeshFileInfo::Chunk const*>(ptr_data_addr);
//    ptr_data_addr += sizeof(*ptr_chunk);

    //
    if( ptr_chunk->IsType(CPL_MFI_CHUNK_KEYLIST) ) // キーリスト
    {
      if( !m_sp_keylist_root ) // ルートが存在していなかったら
      {
        // 新規キーリストを取得
        m_sp_keylist_root = On_NewKeyList( GetLinkMyself() );
        // ファイルから読み込み
        m_sp_keylist_root->zzf_setupData_by_File_
          ( ptr_chunk
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );
      }
      else
      {
        auto ptr_info_keylist =
          static_cast<MFI_AnimeKeyList const*>(ptr_chunk);
        
        // キーリスト作成
        auto sp_keylist = On_NewKeyList( GetLinkMyself() );
        // ファイルから読み込み構築
        sp_keylist->zzf_setupData_by_File_
          ( ptr_chunk
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );

        // 親のキーリストがあれば、親のキーリストを検索して関連付ける
        if( ptr_info_keylist->m_GID_parent )
        {
          auto sp_keylist_parent =
            FindKeyList_by_ID( ptr_info_keylist->m_GID_parent );
          if( sp_keylist_parent )
          {
            sp_keylist_parent->AddLinkChild( sp_keylist );
          }
        }
        else
        {
          // キーリストテーブルに追加
          m_sp_keylist_root->AddLinkEnd( sp_keylist );
        }
      }
    }

    ptr_data_addr += ptr_chunk->m_size;
  }
}


// _____________________________________________________________________________
/// @copydoc doxycomment::func_zzf_setupRelation_
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::AnmData::zzf_setupRelation_
    ( rio<Array_DataSPtr> io_table_for_data_pointer
    , rio<Array_ChunkPtr> io_table_for_chunk_pointer
    )
{
  auto sp_keylist = m_sp_keylist_root;

  while( sp_keylist )
  {
    sp_keylist->zzf_setupRelation_
      ( io_table_for_data_pointer
      , io_table_for_chunk_pointer
      );

    sp_keylist = sp_keylist->GetLinkNextAll();
  }
}


// _____________________________________________________________________________
/// @brief 後始末
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnmData::Release()
{
  auto sp_keylist = m_sp_keylist_root;

  while( sp_keylist )
  {
    sp_keylist->Release();

    sp_keylist = sp_keylist->GetLinkNextAll();
  }
}


// _____________________________________________________________________________
/// @brief 関連付け
/// 
/// @param[in] in_sp_mesh_for_relation
///   : メッシュオブジェクトを指すポインタを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::AnmData::SetRelation
    ( _in<sdptr<MeshData>> in_sp_mesh_for_relation
    )
{ 
  auto sp_keylist = m_sp_keylist_root;

  while( sp_keylist )
  {
    sp_keylist->SetRelation( in_sp_mesh_for_relation );

    sp_keylist = sp_keylist->GetLinkNextAll();
  }
}


// _____________________________________________________________________________
/// @brief アクティブなキーフレームの絶対位置設定
/// 
/// @param[in] in_frame
///   : 絶対位置によるフレームの位置を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnmData::SetPlayKeyFrame( _in<float> in_frame )
{
  auto sp_keylist = m_sp_keylist_root;

  while( sp_keylist )
  {
    sp_keylist->SetPlayKeyFrame( in_frame );

    sp_keylist = sp_keylist->GetLinkNextAll();
  }

  this->m_play_index = in_frame;
}


// _____________________________________________________________________________
/// @brief アクティブなキーフレームの相対位置設定
/// 
/// ※ フレームの移動によるイベントが考慮されます。\n
///    例えば途中にジャンプやループイベントがある場合、それらが実行された状態
/// 
/// @param[in] in_add_frame
///   : フレームの移動量を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnmData::MovePlayKeyFrame( _in<float> in_add_frame )
{
  auto add_frame = in_add_frame;
  if( !m_sp_keylist_root )
  {
    return;
  }

  // 待機検査
  if( m_wait_frame > 0 )
  {
    if( m_wait_frame > add_frame )
    {
      m_wait_frame -= add_frame;
      return;
    }
    else
    {
      add_frame -= m_wait_frame;
      m_wait_frame = 0;
    }
  }

  float next_frame = this->m_play_index + add_frame;
  // イベントキーリストのチェック（ルートはイベントキーリストとなる）
  auto sp_keylist_event = m_sp_keylist_root;

  auto sp_keyframe      = sp_keylist_event->GetActiveKeyFrame();
  auto sp_keyframe_next = sp_keyframe->GetLinkNext();
  auto sp_keyframe_end  = sp_keylist_event->m_wp_keyframe_end.lock();

  while( sp_keyframe )
  {
    float sub_frame = next_frame - sp_keyframe_next->m_index; // 次のキーフレームからの差分フレーム

    if( sub_frame >= 0 ) // 次のキーフレーム以上だったら
    {
      // イベント検査
      auto ptr_keyframe_event =
        static_cast<KeyEvent const*>( &*sp_keyframe_next );
      switch( ptr_keyframe_event->m_ev_type )
      {
      case 'WAIT': // wait
        if( ptr_keyframe_event->m_ev_value > add_frame )
        {
          m_wait_frame = ptr_keyframe_event->m_ev_value - add_frame;
          return;
        }
        break;

      case 'LPED': // loop end
        {
          // ループ始端の検索
          auto sp_keyframe_prev = sp_keyframe_next->GetLinkPrev();
          auto sp_keyframe_top  = sp_keylist_event->m_sp_keyframe_top;

          while( sp_keyframe_prev != sp_keyframe_top )
          {
            if( static_cast<KeyEvent*>(&*sp_keyframe_prev)->m_ev_type == 1 ) // ループ始端ならば
            {
              break;
            }
            sp_keyframe_prev = sp_keyframe_prev->GetLinkPrev();
          }

          // 
          m_play_index      = static_cast<float>(sp_keyframe_prev->m_index); // 再生フレーム設定
          add_frame      = sub_frame;                                        // ループ始端からの追加フレーム数に補正
          next_frame        = m_play_index + sub_frame;                         // 次へのフレーム数を補正
          sp_keyframe_next  = sp_keyframe_prev->GetLinkNext();                   // 次のキーフレームポインタを補正
          // 一度、イベントキーリスト以外のキーリストを設定する
          auto sp_keylist = sp_keylist_event->GetLinkNext();
          while( sp_keylist )
          {
            sp_keylist->SetPlayKeyFrame( m_play_index );

            sp_keylist = sp_keylist->GetLinkNextAll();
          }

          continue; // さらにチェックのため回す
        }
        break;
      }
    }
    else
    {
      this->m_play_index += add_frame;
    }

    break;
  }

  // ここからの処理は、イベント処理が完全に終わった場合のみ処理される（はず）

  // イベントキーリスト以外のキーフレームを設定
  auto sp_keylist = sp_keylist_event->GetLinkNext();
  while( sp_keylist )
  {
    sp_keylist->MovePlayKeyFrame( add_frame );

    sp_keylist = sp_keylist->GetLinkNextAll();
  }
}


// _____________________________________________________________________________
/// @brief 最後尾のキーフレームインデックスの取得
/// 
/// @return 最後尾のキーフレームインデックスを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
float MeshData::AnmData::GetMaxIndex() const
{
  float max_frame = 0;
  auto sp_keylist = m_sp_keylist_root;
  while( sp_keylist )
  {
    max_frame = Max( max_frame, sp_keylist->GetMaxIndex() );

    sp_keylist = sp_keylist->GetLinkNextAll();
  }

  return max_frame;
}


// _____________________________________________________________________________
/// @brief IDによるキーリストの検索
/// 
/// @param[in] in_keylist_ID
///   : 検索するキーリストのIDを指定します。
/// 
/// @return
/// 該当したキーリストを指すスマートポインタを返します。\n
/// 該当しない場合nullptr相当のスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmKeyList>
  MeshData::AnmData::FindKeyList_by_ID( _in<TypeGID> in_keylist_ID )
{
  return
    zzf_search_by_ID_<AnmKeyList>
      ( in_keylist_ID
      , m_sp_keylist_root
      );
}

// _____________________________________________________________________________
/// @copydoc MeshData::AnmData::FindKeyList_by_ID
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdcptr<MeshData::AnmKeyList>
  MeshData::AnmData::FindKeyList_by_ID( _in<TypeGID> in_keylist_ID ) const
{
  return
    zzf_search_by_ID_<AnmKeyList const>
      ( in_keylist_ID
      , m_sp_keylist_root
      );
}


// _____________________________________________________________________________
/// @brief 名前によるキーリストの検索
/// 
/// @param[in] in_keylist_name : キーリストの名前を指定します。
/// 
/// 該当したキーリストを指すスマートポインタを返します。\n
/// 該当しない場合nullptr相当のスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmKeyList>
  MeshData::AnmData::FindKeyList_by_Name( pin<char> in_keylist_name )
{
  return
    zzf_search_by_Name_<AnmKeyList>( in_keylist_name, m_sp_keylist_root );
}


// _____________________________________________________________________________
/// @copydoc MeshData::AnmData::FindKeyList_by_Name
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdcptr<MeshData::AnmKeyList>
  MeshData::AnmData::FindKeyList_by_Name( pin<char> in_keylist_name ) const
{
  return
    zzf_search_by_Name_<AnmKeyList const>( in_keylist_name, m_sp_keylist_root );
}


// _____________________________________________________________________________
/// @brief IDによるアクティブなキーリストの設定
/// 
/// @param[in] in_keylist_ID
///   : アクティブにしたいキーリストのIDを指定します。
/// 
/// @return
/// 該当したキーリストを指すスマートポインタを返します。\n
/// 該当しない場合nullptr相当のスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmKeyList>
  MeshData::AnmData::SetActiveKeyList_by_ID( _in<U32> in_keylist_ID )
{
  m_wp_active_keylist = FindKeyList_by_ID( in_keylist_ID );

  return m_wp_active_keylist.lock();
}


// _____________________________________________________________________________
/// @brief 名前によるアクティブなキーリストの設定
/// 
/// @param[in] in_keylist_name
///   : アクティブにしたいキーリストの名前を指定します。
/// 
/// @return
/// 該当したキーリストを指すスマートポインタを返します。\n
/// 該当しない場合nullptr相当のスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmKeyList>
  MeshData::AnmData::SetActiveKeyList_by_Name( pin<char> in_keylist_name )
{
  m_wp_active_keylist = FindKeyList_by_Name( in_keylist_name );

  return m_wp_active_keylist.lock();
}


// _____________________________________________________________________________
/// @brief アクティブなキーリストの設定
/// 
/// @param[in] in_sp_keylist
///   : アクティブにするキーリストのポインタを指定します。
/// 
/// @return 渡したポインタを直接返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmKeyList>
  MeshData::AnmData::SetActiveKeyList_by_Pointer
    ( _in<sdptr<AnmKeyList>> in_sp_keylist
    )
{
  m_wp_active_keylist = in_sp_keylist;

  return m_wp_active_keylist.lock();
}


// _____________________________________________________________________________
/// @brief キーリストの追加
/// 
/// @param[in] in_sp_keylist_parent
///   : 親となるキーリストを指すスマートポインタを指定します。\n
///   : nullptrを指定するとルートのキーリストを親とします。
/// 
/// @return 作成されたキーリストを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmKeyList>
  MeshData::AnmData::AddKeyList( _in<sdptr<AnmKeyList>> in_sp_keylist_parent )
{
  sdptr<AnmKeyList> sp_new_keylist( On_NewKeyList( GetLinkMyself() ) );

  if( in_sp_keylist_parent )
  {
    in_sp_keylist_parent->AddLinkChild( sp_new_keylist );
  }
  else
  if( m_sp_keylist_root )
  {
    m_sp_keylist_root->AddLinkChild( sp_new_keylist );
  }
  else
  {
    m_sp_keylist_root = sp_new_keylist;
  }

  return sp_new_keylist;
}


// _____________________________________________________________________________
/// @brief キーフレームの削除
/// 
/// @param[in] io_keyframe_for_delete
///   : 削除するキーフレームを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  MeshData::AnmData::DelKeyFrame
    ( _in<sdptr<baseKeyFrame>> io_keyframe_for_delete
    )
{
  sdptr<AnmKeyList> sp_keylist = this->m_sp_keylist_root;

  while( sp_keylist )
  {
    if( sp_keylist->DelKeyFrame( io_keyframe_for_delete ) )
    {
      return true;
    }

    sp_keylist = sp_keylist->GetLinkNext();
  }

  return false;
}


// _____________________________________________________________________________
/// @brief 全てのキーフレームの削除
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnmData::DelKeyFrameAll()
{
	SetActiveKeyList( nullptr );

  sdptr<AnmKeyList> sp_keylist = this->m_sp_keylist_root;

  while( sp_keylist )
  {
    sp_keylist->DelKeyFrameAll();
    sp_keylist = sp_keylist->GetLinkNext();
  }
}








// _____________________________________________________________________________
/// @brief デフォルトコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::AnmKeyList::AnmKeyList()
  : m_data_type( MeshFileInfo::eKeyType::BaseKey )
{}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::AnmKeyList::AnmKeyList( cref<AnmKeyList> in_data )
  : td_base( in_data )
  , m_data_type( in_data.GetKeyKindType() )
  , m_wp_relation_data( in_data.m_wp_relation_data )
{
  if( in_data.m_sp_keyframe_top )
  {
    //***** キーフレームコピー *****//
    sdptr<baseKeyFrame> sp_key_src = in_data.m_sp_keyframe_top;
    m_sp_keyframe_top =
      std::dynamic_pointer_cast<baseKeyFrame>(sp_key_src->CreateClone()); // クローン保持。
    sp_key_src = sp_key_src->GetLinkNext();
    sdptr<baseKeyFrame> sp_key_dest = m_sp_keyframe_top;
    // 後続ノードのコピーループ
    while( sp_key_src )
    {
      sdptr<baseKeyFrame>
        sp_key_clone =
          std::dynamic_pointer_cast<baseKeyFrame>( sp_key_src->CreateClone() );
      sp_key_dest->AddLinkNext( sp_key_clone );

      sp_key_dest = sp_key_clone;
    }
  }
}


// _____________________________________________________________________________
/// @brief ムーブコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::AnmKeyList::AnmKeyList( rvref<AnmKeyList> in_data )
  : td_base( std::move(in_data) )
  , m_data_type( in_data.GetKeyKindType() )
  , m_wp_relation_data( std::move(in_data.m_wp_relation_data) )
{
  if( in_data.m_sp_keyframe_top )
  {
    //***** キーフレームコピー *****//
    sdptr<baseKeyFrame> sp_key_src = in_data.m_sp_keyframe_top;
    m_sp_keyframe_top =
      std::dynamic_pointer_cast<baseKeyFrame>(sp_key_src->CreateClone()); // クローン保持。
    sp_key_src = sp_key_src->GetLinkNext();
    sdptr<baseKeyFrame> sp_key_dest = m_sp_keyframe_top;
    // 後続ノードのコピーループ
    while( sp_key_src )
    {
      sdptr<baseKeyFrame>
        sp_key_clone =
          std::dynamic_pointer_cast<baseKeyFrame>( sp_key_src->CreateClone() );
      sp_key_dest->AddLinkNext( sp_key_clone );

      sp_key_dest = sp_key_clone;
    }
  }
}


// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @param[in] in_sp_anm_data
///   : アニメオブジェクトを指すスマートポインタを指定します。\n
///   : 自身が属するアニメとして関連付けされます。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::AnmKeyList::AnmKeyList( _in<sdcptr<AnmData>> in_sp_anm_data )
  : m_wp_anime_data( in_sp_anm_data )
  , m_data_type( MeshFileInfo::eKeyType::BaseKey )
{}


// _____________________________________________________________________________
/// @brief ファイルデータからデータ構築
/// 
/// @param[in] in_ptr_chunk
///   : チャンクポインタを指定します。
/// @copydetails doxycomment::arg_io_table_for_data_pointer
/// @copydetails doxycomment::arg_io_table_for_chunk_pointer
/// 
/// @return 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::AnmKeyList::zzf_setupData_by_File_
    ( pin<MeshFileInfo::Chunk> in_ptr_chunk
    , rio<Array_DataSPtr     > io_table_for_data_pointer
    , rio<Array_ChunkPtr     > io_table_for_chunk_pointer
    )
{
  char_cptr ptr_data_addr = reinterpret_cast<char_cptr>(in_ptr_chunk);
  auto* ptr_info_keylist =
    static_cast<MFI_AnimeKeyList const*>(in_ptr_chunk);
  // データポインタ登録。
  io_table_for_data_pointer.Add
    ( ptr_info_keylist->m_GID
    , this->GetLinkMyself()
    );
  // チャンクポインタ登録。
  io_table_for_chunk_pointer.Add( this, in_ptr_chunk );
  // アドレス調整
  ptr_data_addr =
    reinterpret_cast<char_cptr>(ptr_info_keylist + 1) - sizeof(MFI_baseKeyFrame);
  //
  U32  key_num     = ptr_info_keylist->m_key_num;
  U32  type_size   = 0;
  auto type        =
       m_data_type = ptr_info_keylist->m_key_type;
  // タイプ判定
  switch( type )
  {
  case MeshFileInfo::eKeyType::Event:
    type_size = sizeof(KeyEvent);
    break;
  case MeshFileInfo::eKeyType::VectorPos:
  case MeshFileInfo::eKeyType::VectorRot:
  case MeshFileInfo::eKeyType::VectorScl:
    type_size = sizeof(KeyVector);
    break;
  case MeshFileInfo::eKeyType::Param0: type_size = sizeof(KeyParam1); break;
  case MeshFileInfo::eKeyType::Param1: type_size = sizeof(KeyParam2); break;
  case MeshFileInfo::eKeyType::Param2: type_size = sizeof(KeyParam3); break;
  case MeshFileInfo::eKeyType::Param3: type_size = sizeof(KeyParam4); break;

  case MeshFileInfo::eKeyType::ColorDiffuse:
  case MeshFileInfo::eKeyType::ColorSpecular:
  case MeshFileInfo::eKeyType::ColorEmissive:
    type_size = sizeof(KeyColor);
    break;
  case MeshFileInfo::eKeyType::MaterialPower:
  case MeshFileInfo::eKeyType::LightPower:
    type_size = sizeof(KeyParam1);
    break;
  case MeshFileInfo::eKeyType::TexCoord:
    type_size = sizeof(KeyTexCoord);
    break;
  default:
    break;
  }

  // キーフレーム追加
  for( U32 i = 0; i < key_num; ++i )
  {
    switch( type )
    {
    case MeshFileInfo::eKeyType::Event:
      AddKeyFrame( CPL_MAKE_SHARED( KeyEvent, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::VectorPos:
      AddKeyFrame( CPL_MAKE_SHARED( KeyVecPos, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::VectorRot:
      AddKeyFrame( CPL_MAKE_SHARED( KeyVecRot, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::VectorScl:
      AddKeyFrame( CPL_MAKE_SHARED( KeyVecScl, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::Param0:
      AddKeyFrame( CPL_MAKE_SHARED( KeyParam1, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::Param1:
      AddKeyFrame( CPL_MAKE_SHARED( KeyParam2, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::Param2:
      AddKeyFrame( CPL_MAKE_SHARED( KeyParam3, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::Param3:
      AddKeyFrame( CPL_MAKE_SHARED( KeyParam4, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::ColorDiffuse:
    case MeshFileInfo::eKeyType::ColorSpecular:
    case MeshFileInfo::eKeyType::ColorEmissive:
    case MeshFileInfo::eKeyType::ColorAmbient:
      AddKeyFrame( CPL_MAKE_SHARED( KeyColor, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::LightPower:
      AddKeyFrame( CPL_MAKE_SHARED( KeyLightPower, ptr_data_addr ) );
      break;
    case MeshFileInfo::eKeyType::TexCoord:
      AddKeyFrame( CPL_MAKE_SHARED( KeyTexCoord, ptr_data_addr ) );
      break;
    default:
      break;
    }
  }
}


// _____________________________________________________________________________
/// @brief 関連付けデータ等の設定
/// 
/// @copydetails doxycomment::arg_io_table_for_data_pointer
/// @copydetails doxycomment::arg_io_table_for_chunk_pointer
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::AnmKeyList::zzf_setupRelation_
    ( rio<Array_DataSPtr> io_table_for_data_pointer
    , rio<Array_ChunkPtr> io_table_for_chunk_pointer
    )
{
  MeshFileInfo::Chunk const** pp_chunk_info = io_table_for_chunk_pointer.Find( this );
  if( !pp_chunk_info  ||  !*pp_chunk_info )
  {
    return;
  }
  MFI_AnimeKeyList const* ptr_info_keylist =
    static_cast<MFI_AnimeKeyList const*>( *pp_chunk_info );

  m_data_type = ptr_info_keylist->m_key_type;

  void_sptr* psp_data;
  // 次のキーリスト
  psp_data = io_table_for_data_pointer.Find( ptr_info_keylist->m_GID_next );
  sdptr<AnmKeyList>
    sp_keylist_next =
       psp_data ? std::static_pointer_cast<AnmKeyList>(*psp_data)
                : nullptr;
  if( sp_keylist_next )
  {
    AddLinkNext( sp_keylist_next );
  }

  // 子供キーリスト
  psp_data = io_table_for_data_pointer.Find( ptr_info_keylist->m_GID_next );
  sdptr<AnmKeyList>
    sp_keylist_child =
      psp_data ? std::static_pointer_cast<AnmKeyList>(*psp_data)
               : nullptr;
  if( sp_keylist_child )
  {
    AddLinkChild( sp_keylist_child );
  }

  // 関連付けデータ
  psp_data = io_table_for_data_pointer.Find( ptr_info_keylist->m_GID_relation );
  m_wp_relation_data =
    psp_data ? std::static_pointer_cast<baseData>(*psp_data)
             : nullptr;

  // テクスチャセットのキーフレームの場合、テクスチャセットへのリンクを設定する。
  if( this->m_data_type == MeshFileInfo::eKeyType::TexCoord )
  {
    sdptr<baseKeyFrame> sp_keyframe = m_sp_keyframe_top;

    while( sp_keyframe )
    {
      sdptr<KeyTexCoord>
        sp_key_texcoord =
          std::dynamic_pointer_cast<KeyTexCoord>(sp_keyframe);
      if( sp_key_texcoord ) // KeyTexCoord型に変換できる場合。
      {
        // 関連付けられているデータを検索。
        psp_data = io_table_for_data_pointer.Find( sp_key_texcoord->m_GID_tex );
        sdptr<TexCoordSet>
          sp_texcoordset =
            psp_data ? std::static_pointer_cast<TexCoordSet>(*psp_data)
                     : nullptr;
        sp_key_texcoord->m_wp_relation_texcoordset = sp_texcoordset;
      }

      sp_keyframe = sp_keyframe->GetLinkNext();
    }
  }

//  m_ptr_info_keylist = nullptr;
}


// _____________________________________________________________________________
/// @brief キーフレームポインタから、キーフォーマットを取得
/// 
/// @param[in] in_sp_keyframe
///   : キーフレームを指すスマートポインタを指定します。
/// 
/// @return キーフォーマットを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshFileInfo::eKeyType
  MeshData::AnmKeyList::zzf_getKeyType_to_KeyPointer
    ( _in<sdptr<baseKeyFrame>> in_sp_keyframe
    ) const
{
  // 一度生ポインタに。
  baseKeyFrame* ptr_keyframe = &*in_sp_keyframe;

  if( typeid(ptr_keyframe) == typeid(KeyEvent*) )
  {
    return MeshFileInfo::eKeyType::Event;
  }
  else
  if( typeid(ptr_keyframe) == typeid(KeyVecPos*) )
  {
    return MeshFileInfo::eKeyType::VectorPos;
  }
  else
  if( typeid(ptr_keyframe) == typeid(KeyVecRot*) )
  {
    return MeshFileInfo::eKeyType::VectorRot;
  }
  else
  if( typeid(ptr_keyframe) == typeid(KeyVecScl*) )
  {
    return MeshFileInfo::eKeyType::VectorScl;
  }
  else
  if( typeid(ptr_keyframe) == typeid(KeyColor*) )
  {
    return MeshFileInfo::eKeyType::Color0;
  }
  else
  if( typeid(ptr_keyframe) == typeid(KeyMtrlPower*) )
  {
    return MeshFileInfo::eKeyType::MaterialPower;
  }
  else
  if( typeid(ptr_keyframe) == typeid(KeyLightPower*) )
  {
    return MeshFileInfo::eKeyType::LightPower;
  }
  else
  if( typeid(ptr_keyframe) == typeid(KeyTexCoord*) )
  {
    return MeshFileInfo::eKeyType::TexCoord;
  }

  return MeshFileInfo::eKeyType::None; // 該当無し
}


// _____________________________________________________________________________
/// @brief 後始末
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnmKeyList::Release()
{
  m_sp_keyframe_top = nullptr;
}


// _____________________________________________________________________________
/// @brief 関連付け
/// 
/// @param[in] in_sp_mesh
///   : キーリストが属したいメッシュを指すポインタを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnmKeyList::SetRelation( _in<sdptr<MeshData>> in_sp_mesh )
{
  if( auto sp_relation_data = m_wp_relation_data.lock() )
  {
    auto sp_myself = this->GetLinkMyself();

    // オブジェクト
    if( auto* ptr_object = dynamic_cast<Object*>(&*sp_relation_data) )
    {
      switch( this->m_data_type )
      {
      case MeshFileInfo::eKeyType::VectorPos:
        ptr_object->m_wp_relation_keylist_pos = sp_myself;
        break;
      case MeshFileInfo::eKeyType::VectorRot:
        ptr_object->m_wp_relation_keylist_rot = sp_myself;
        break;
      case MeshFileInfo::eKeyType::VectorScl:
        ptr_object->m_wp_relation_keylist_scl = sp_myself;
        break;
      case MeshFileInfo::eKeyType::TexCoord:
        {
          sdptr<KeyTexCoord> sp_key_tex =
            std::dynamic_pointer_cast<KeyTexCoord>(this->m_sp_keyframe_top);
          if( sp_key_tex )
          {
            ptr_object->m_wp_relation_texcoordset =
              sp_key_tex->m_wp_relation_texcoordset;
          }
          else
          {
            ptr_object->m_wp_relation_texcoordset.reset();
          }
        }
        break;
      default:
        break;
      }
    }
    // ボーン
    else
    if( auto* ptr_bone = dynamic_cast<Bone*>(&*sp_relation_data) )
    {
      switch( this->m_data_type )
      {
      case MeshFileInfo::eKeyType::VectorPos:
        ptr_bone->m_wp_relation_keylist_pos = sp_myself;
        break;
      case MeshFileInfo::eKeyType::VectorRot:
        ptr_bone->m_wp_relation_keylist_rot = sp_myself;
        break;
      case MeshFileInfo::eKeyType::VectorScl:
        ptr_bone->m_wp_relation_keylist_scl = sp_myself;
        break;
      default:
        break;
      }
    }
    // マテリアル
    else
    if( auto* ptr_material = dynamic_cast<ColorMaterial*>(&*sp_relation_data) )
    {
      switch( this->m_data_type )
      {
      case MeshFileInfo::eKeyType::Param0:
        ptr_material->m_wp_relation_keylist_color[0] = sp_myself;
        break;
      case MeshFileInfo::eKeyType::Param1:
        ptr_material->m_wp_relation_keylist_color[1] = sp_myself;
        break;
      case MeshFileInfo::eKeyType::Param2:
        ptr_material->m_wp_relation_keylist_color[2] = sp_myself;
        break;
      case MeshFileInfo::eKeyType::Param3:
        ptr_material->m_wp_relation_keylist_color[3] = sp_myself;
        break;
      default:
        break;
      }
    }
    // ライト
    else
    if( auto* ptr_light_mtrl = dynamic_cast<LightMaterial*>(&*sp_relation_data) )
    {
      switch( this->m_data_type )
      {
      case MeshFileInfo::eKeyType::VectorPos:
        ptr_light_mtrl->m_wp_relation_keylist_pos = sp_myself;
        break;
      case MeshFileInfo::eKeyType::VectorRot:
        ptr_light_mtrl->m_wp_relation_keylist_rot = sp_myself;
        break;
      case MeshFileInfo::eKeyType::ColorDiffuse:
      case MeshFileInfo::eKeyType::ColorSpecular:
      case MeshFileInfo::eKeyType::ColorEmissive:
        ptr_light_mtrl->m_wp_relation_keylist_color = sp_myself;
        break;
      case MeshFileInfo::eKeyType::LightPower:
        ptr_light_mtrl->m_wp_relation_keylist_power = sp_myself;
        break;
      default:
        break;
      }
    }
  }
}


// _____________________________________________________________________________
/// @copydoc MeshData::AnmData::SetPlayKeyFrame
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnmKeyList::SetPlayKeyFrame( _in<float> in_frame )
{
  m_wp_keyframe_active = FindPrevKeyFrame_by_Frame( in_frame );
}


// _____________________________________________________________________________
/// @copydoc MeshData::AnmData::MovePlayKeyFrame
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnmKeyList::MovePlayKeyFrame( _in<float> in_add_frame )
{
  if( auto sp_anm = m_wp_anime_data.lock() )
  {
    float set_frame = in_add_frame + sp_anm->GetPlayIndex();

    while( !m_wp_keyframe_active.expired()  &&
           m_wp_keyframe_active.lock() != m_wp_keyframe_end.lock() )
    {
      if( m_wp_keyframe_active.lock()->m_index > set_frame )
      {
        break;
      }
      m_wp_keyframe_active = m_wp_keyframe_active.lock()->GetLinkNext();
    }
  }
}


// _____________________________________________________________________________
/// @brief 直前のキーフレームを検索
/// 
/// @param[in] in_frame
///   : 先頭からの絶対的なフレーム位置を指定します。
/// 
/// @return
/// 該当したキーフレームを指すスマートポインタを返します。\n
/// 該当しなかった場合、nullptrを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::baseKeyFrame>
  MeshData::AnmKeyList::FindPrevKeyFrame_by_Frame( _in<float> in_frame ) const
{
  if( !m_sp_keyframe_top  ||  m_wp_keyframe_end.expired() )
  {
    return nullptr;
  }
  else
  {
    // 
    auto sp_check_key = m_wp_keyframe_end.lock();
    while( sp_check_key )
    {
      if( sp_check_key->m_index <= in_frame )
      {
        return sp_check_key;
      }

      sp_check_key = sp_check_key->GetLinkPrev();
    }
  }

  // 該当無し
  return nullptr;
}


// _____________________________________________________________________________
/// @brief 直後のキーフレームを検索
/// 
/// @param[in] in_frame
///   : 先頭からの絶対的なフレーム位置を指定します。
/// 
/// @return
/// 該当したキーフレームを指すスマートポインタを返します。\n
/// 該当しなかった場合、nullptrを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::baseKeyFrame>
  MeshData::AnmKeyList::FindNextKeyFrame_by_Frame( _in<float> in_frame ) const
{
  if( !m_sp_keyframe_top  ||  m_wp_keyframe_end.expired() )
  {
    return nullptr;
  }
  else
  {
    //
    auto sp_check_key = m_sp_keyframe_top;
    while( sp_check_key )
    {
      if( sp_check_key->m_index >= in_frame )
      {
        return sp_check_key;
      }

      sp_check_key = sp_check_key->GetLinkNext();
    }
  }

  return nullptr;
}


// _____________________________________________________________________________
/// @brief 指定したキーフレームを保持しているかチェック
/// 
/// @param[in] in_sp_keyframe
///   : キーフレームを指すスマートポインタを指定します。
/// 
/// @retval true  : 指定したキーフレームを保持している。
/// @retval false : 指定したキーフレームを保持していない。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  MeshData::AnmKeyList::IsKeyFrame
    ( _in<sdptr<baseKeyFrame>> in_sp_keyframe
    ) const
{
  auto sp_key = this->m_sp_keyframe_top;
  while( sp_key )
  {
    if( sp_key == in_sp_keyframe )
    {
      return true;
    }

    sp_key = sp_key->GetLinkNext();
  }

  return false;
}


// _____________________________________________________________________________
/// @brief タイプに順ずる新しいキーフレームを取得
/// 
/// @param[in] in_index_of_keyframe
/// @copydetails doxycomment::arg_in_flag_interpolate
/// 
/// @return 新しく作成されたキーフレームを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::baseKeyFrame>
  MeshData::AnmKeyList::NewDefaultKeyFrame
    ( _in<U32 > in_index_of_keyframe
    , _in<bool> in_flag_interpolate
    ) const
{
  switch( m_data_type )
  {
  case MeshFileInfo::eKeyType::VectorPos:
    return CPL_MAKE_SHARED( KeyVecPos, in_index_of_keyframe, in_flag_interpolate );
  case MeshFileInfo::eKeyType::VectorRot:
    return CPL_MAKE_SHARED( KeyVecRot, in_index_of_keyframe, in_flag_interpolate );
  case MeshFileInfo::eKeyType::VectorScl:
    return CPL_MAKE_SHARED( KeyVecScl, in_index_of_keyframe, in_flag_interpolate );

  case MeshFileInfo::eKeyType::Color0:
  case MeshFileInfo::eKeyType::Color1:
  case MeshFileInfo::eKeyType::Color2:
  case MeshFileInfo::eKeyType::Color3:
    return CPL_MAKE_SHARED( KeyColor, in_index_of_keyframe, in_flag_interpolate, float4(1,1,1,1) );

  case MeshFileInfo::eKeyType::Param0:
    return CPL_MAKE_SHARED( KeyParam1, in_index_of_keyframe, in_flag_interpolate, 0.0f );
  case MeshFileInfo::eKeyType::Param1:
    return CPL_MAKE_SHARED( KeyParam2, in_index_of_keyframe, in_flag_interpolate, 0.0f, 0.0f );
  case MeshFileInfo::eKeyType::Param2:
    return CPL_MAKE_SHARED( KeyParam3, in_index_of_keyframe, in_flag_interpolate, 0.0f, 0.0f, 0.0f );
  case MeshFileInfo::eKeyType::Param3:
    return CPL_MAKE_SHARED( KeyParam4, in_index_of_keyframe, in_flag_interpolate, 0.0f, 0.0f, 0.0f, 0.0f );

  case MeshFileInfo::eKeyType::Event:
  default:
    return CPL_MAKE_SHARED( KeyEvent, in_index_of_keyframe, in_flag_interpolate, 0, 0 );
  }
}


// _____________________________________________________________________________
/// @brief キーフレームの追加
/// 
/// @param[in] io_sp_keyframe
///   : 追加するキーフレームを指すスマートポインタを指定します。
/// 
/// @return 追加されたキーフレームを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::baseKeyFrame>
  MeshData::AnmKeyList::AddKeyFrame( _in<sdptr<baseKeyFrame>> io_sp_keyframe )
{
  // 追加対象キーフレームのキータイプを求める
  MeshFileInfo::eKeyType
    key_type = zzf_getKeyType_to_KeyPointer( io_sp_keyframe );
  if( key_type == MeshFileInfo::eKeyType::None )
  {
    return nullptr;
  }

  // キーフレームが一つも無い場合
  if( !m_sp_keyframe_top )
  {
    m_sp_keyframe_top = io_sp_keyframe;
    m_wp_keyframe_end = io_sp_keyframe;

    io_sp_keyframe->m_index = 0;
    this->m_data_type = key_type;
  }
  else
  {
    // 追加タイプが現在のタイプと違っていたら抜ける
    if( this->m_data_type != key_type )
    {
      return nullptr;
    }

    // 追加対象の前のキーフレームを取得
    sdptr<baseKeyFrame> sp_add_prev_keyframe = m_sp_keyframe_top;
    const U32 new_index = io_sp_keyframe->m_index;

    while( sp_add_prev_keyframe->m_index < new_index )
    {
      sp_add_prev_keyframe = sp_add_prev_keyframe->GetLinkNext();
    }

    // 追加
    sp_add_prev_keyframe->AddLinkNext( io_sp_keyframe );

    if( sp_add_prev_keyframe->m_index == new_index )
    {
      // 先頭と同じならば
      if( m_sp_keyframe_top == sp_add_prev_keyframe )
      {
        m_sp_keyframe_top->Detach();
        m_sp_keyframe_top = io_sp_keyframe;
      }
      // 最後尾と同じならば
      if( m_wp_keyframe_end.lock() == sp_add_prev_keyframe )
      {
        m_wp_keyframe_end.lock()->Detach();
        m_wp_keyframe_end = io_sp_keyframe;
      }
    }
  }

  return io_sp_keyframe;
}


// _____________________________________________________________________________
/// @brief キーフレームの削除
/// 
/// @param[in] io_keyframe_for_delete
///   : 削除するキーフレームを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗（渡されたキーフレームが管理下にない等）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  MeshData::AnmKeyList::DelKeyFrame
    ( _in<sdptr<baseKeyFrame>> io_keyframe_for_delete
    )
{
  if( io_keyframe_for_delete != nullptr )
  {
    // 指定されたキーフレームが自身が保持するキーフレームでなければ抜ける
    if( !this->IsKeyFrame( io_keyframe_for_delete ) )
    {
      return false;
    }

    // 先頭キーフレームの調整
    if( io_keyframe_for_delete == this->m_sp_keyframe_top )
    {
      this->m_sp_keyframe_top = io_keyframe_for_delete->GetLinkNext();
    }
    // 最後尾キーフレームの調整
    if( io_keyframe_for_delete == this->m_wp_keyframe_end.lock() )
    {
      this->m_wp_keyframe_end = io_keyframe_for_delete->GetLinkPrev();
    }
    // アクティブキーフレームの設定
    SetActiveKeyFrame( io_keyframe_for_delete->GetLinkNext() );

    // 連結リストから解除
    io_keyframe_for_delete->Detach();

    return true;
  }

  return false;
}


// _____________________________________________________________________________
/// @brief 保持するキーフレームを全て削除
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::AnmKeyList::DelKeyFrameAll()
{
  auto sp_key = this->m_wp_keyframe_end.lock();

  if( sp_key )
  {
    auto detach_sp_key = sp_key;
    sp_key = sp_key->GetLinkPrev();

    detach_sp_key->Detach();
  }
}


// _____________________________________________________________________________
/// @brief キーフレームリストのペースト
/// 
/// @param[in] in_keylist_for_copysource
///   : コピー元のキーリストを指すスマートポインタを指定します。
/// @param[in] in_insert_frame
///   : 挿入位置フレームを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::AnmKeyList::PastKeyList
    ( cref<AnmKeyList> in_keylist_for_copysource
    , _in <int       > in_insert_frame
    )
{
  auto sp_key = this->m_sp_keyframe_top;

  while( sp_key )
  {
    if( static_cast<int>(sp_key->m_index) > in_insert_frame )
    {
      // 追加対象のキーフレームリストを回す。
      auto sp_key_add = in_keylist_for_copysource.m_sp_keyframe_top;
      while( sp_key_add )
      {
        // 追加
        sp_key->AddLinkPrev( sp_key_add );
        // 次のキー
        sp_key_add = sp_key_add->GetLinkNext();
      }
    }
    //
    sp_key = sp_key->GetLinkNext();
  }
}




// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydetails doxycomment::arg_io_ptr_key_data
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::KeyEvent::KeyEvent( rio<char_cptr> io_ptr_key_data )
  : baseKeyFrame( io_ptr_key_data )
{
  auto ptr_key_event =
    reinterpret_cast<MFI_KeyEvent const*>(io_ptr_key_data);
  m_ev_type  = ptr_key_event->m_ev_type;
  m_ev_value = ptr_key_event->m_ev_value;

  io_ptr_key_data += sizeof(*ptr_key_event);
}


// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydetails doxycomment::arg_io_ptr_key_data
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::KeyVector::KeyVector( rio<char_cptr> io_ptr_key_data )
  : baseKeyFrame( io_ptr_key_data )
{
  auto ptr_key_vec =
    reinterpret_cast<MFI_KeyVector const*>(io_ptr_key_data);
  this->m_vec = ptr_key_vec->m_vec;

  io_ptr_key_data += sizeof(*ptr_key_vec);
}


// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydetails doxycomment::arg_io_ptr_key_data
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::KeyColor::KeyColor( rio<char_cptr> io_ptr_key_data )
  : baseKeyFrame( io_ptr_key_data )
{
  auto ptr_key_color =
    reinterpret_cast<MFI_KeyColor const*>(io_ptr_key_data);
  this->m_color =
    float4
      ( ptr_key_color->m_color.GetR() / 255.0f
      , ptr_key_color->m_color.GetG() / 255.0f
      , ptr_key_color->m_color.GetB() / 255.0f
      , ptr_key_color->m_color.GetA() / 255.0f
      );

  io_ptr_key_data += sizeof(*ptr_key_color);
}


// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydetails doxycomment::arg_io_ptr_key_data
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::KeyTexCoord::KeyTexCoord( rio<char_cptr> io_ptr_key_data )
  : baseKeyFrame( io_ptr_key_data )
{
  auto ptr_key_tex =
    reinterpret_cast<MFI_KeyTexCoord const*>(io_ptr_key_data);
  //m_wp_relation_texcoordset =
  //  reinterpret_cast<baseData*>(ptr_key_tex->m_GID_texture); // 一時的にポインタにIDを格納する
  m_GID_tex = ptr_key_tex->m_GID_texture;

  io_ptr_key_data += sizeof(*ptr_key_tex);
}




} // namespace CDI
} // namespace CPL