/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2009/X/X - 2016/12/23
/// 
/// @brief  メッシュデータ構造
/// 
/// ****************************************************************************

#include "CPL_CDI_MeshData.h"

namespace CPL {
namespace CDI {

  
/// @cond
// _____________________________________________________________________________
// キーリストから現在のベクトルを取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::baseData::zzf_getKeyListVec
    ( _in <sdptr<baseData>> in_sp_keylist
    , _in <bool           > in_flag_interpolate
    , rout<CVector3       > out_vec
    ) const
{
  sdptr<AnmKeyList> sp_anm_keylist =
    std::dynamic_pointer_cast<AnmKeyList>(in_sp_keylist);

  if( sp_anm_keylist )
  {
    float frame = sp_anm_keylist->GetAnimation()->GetPlayIndex();
    // アクティブなキーフレームを取得
    auto sp_key_vec =
      std::dynamic_pointer_cast<KeyVector const>
        ( sp_anm_keylist->GetActiveKeyFrame() );

    if( sp_key_vec )
    {
      if( sp_key_vec->m_interpolate )
      {
        auto sp_key_vec_next =
          std::dynamic_pointer_cast<KeyVector const>
            ( sp_anm_keylist->GetActiveKeyFrameNext() );

        if( sp_key_vec_next )
        {
          // 補間
          auto& v0 = sp_key_vec->m_vec;
          auto& v1 = sp_key_vec_next->m_vec;
          float a = (frame - sp_key_vec->m_index) / (sp_key_vec_next->m_index - sp_key_vec->m_index);
          CVector3
            v( v0.x + (v1.x - v0.x) * a
             , v0.y + (v1.y - v0.y) * a
             , v0.z + (v1.z - v0.z) * a
             );
          //
          out_vec = v;
        }
      }
      else
      {
        out_vec = sp_key_vec->m_vec;
      }
    }
  }
}
/// @endcond





// _____________________________________________________________________________
/// @brief コンストラクタ（メモリストリームversion）
/// 
/// @param[in] in_stream_for_memory
///   : メッシュデータを指すメモリストリームオブジェクトを指定します。
/// @param[in] in_ptr_d3d_dev
///   : DirectXデバイスポインタを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::MeshData
( _in<Core::MemoryStream> in_stream_for_memory
, _in<DX::DXDevice*     > in_ptr_d3d_dev
)
{
  zzf_create( in_stream_for_memory, in_ptr_d3d_dev );
}


// _____________________________________________________________________________
/// @brief コンストラクタ（ファイルストリームversion）
/// 
/// @param[in] in_file_stream
///   : メッシュデータを指すファイルストリームを指定します。
/// @param[in] in_ptr_d3d_dev
///   : DirectXデバイスへのポインタを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::MeshData
( _in<Core::FileStream> in_file_stream
, _in<DX::DXDevice*   > in_ptr_d3d_dev
)
{
  Core::MemoryStream buf;
  in_file_stream >> buf;

  in_file_stream.GetPath( m_path );

  zzf_create( buf, in_ptr_d3d_dev );
}


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


// _____________________________________________________________________________
/// @brief データ構築 ＆ データリンク
/// 
/// @param[in] in_stream_for_memory
///   : メッシュデータを指すメモリストリームオブジェクトを指定します。
/// @param[in] in_ptr_d3d_dev
///   : DirectXデバイスポインタを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::zzf_create
    ( _in<Core::MemoryStream> in_stream_for_memory
    , pio<DX::DXDevice      > in_ptr_d3d_dev
    )
{
  // データポインタテーブル
  Array_DataSPtr data_sp_table;
  data_sp_table.Reserve( 1024 );
  // チャンクポインタテーブル
  Array_ChunkPtr chunk_ptr_table;
  chunk_ptr_table.Reserve( 1024 );

  //
  zzf_setupData_by_File_
    ( in_stream_for_memory
    , in_ptr_d3d_dev
    , data_sp_table
    , chunk_ptr_table
    );

  zzf_setupRelation_( data_sp_table, chunk_ptr_table );
}


// _____________________________________________________________________________
/// @brief データ構築
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::zzf_setupData_by_File_
    ( _in<Core::MemoryStream> in_stream_for_memory
    , _in<DX::DXDevice*     > in_ptr_d3d_dev
    , rio<Array_DataSPtr    > io_table_for_data_pointer
    , rio<Array_ChunkPtr    > io_table_for_chunk_pointer
    )
{
  m_wp_object_root.reset();

  try {
    // ファイルヘッダ
    char_cptr ptr_data_addr =
      static_cast<char_cptr>(in_stream_for_memory.GetTopAddr());

    MFI_Header const* ptr_info_header =
      reinterpret_cast<MFI_Header const*>(ptr_data_addr);

    char_cptr ptr_data_end_addr =
      ptr_data_addr + ptr_info_header->m_size;

    ptr_data_addr += sizeof(MFI_Header); // アドレス補正
    if( ptr_info_header->IsType( CPL_MFI_CHUNK_HEAD ) )
    {
      CPL_THROW_CODE
        ( static_cast<int>(eErrorCode::NotCore4dFile)
        , "指定されたファイルはCorePLiメッシュファイルではない\n"
        );
    }

    // チャンクループ
    while( ptr_data_addr < ptr_data_end_addr )
    {
      // チャンク
      MeshFileInfo::Chunk const* ptr_chunk =
        reinterpret_cast<MeshFileInfo::Chunk const*>(ptr_data_addr);
//      ptr_data_addr += sizeof(MeshFileInfo::Chunk); // アドレス補正

      //********** 頂点レイアウト **********//
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_VTXDECL ) )
      {
        // 頂点レイアウトの作成
        auto sp_layout_buf =
          CPL_MAKE_SHARED( LayoutBuffer, in_ptr_d3d_dev );
        //
        sp_layout_buf->zzf_setupData_by_File_
          ( ptr_chunk
          , in_ptr_d3d_dev
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );
        //
        this->m_vtxlayout_sp_table.push_back( sp_layout_buf );
      }
      //********** オブジェクト **********//
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_OBJECT ) )
      {
        // オブジェクト作成
        auto sp_new_object = On_NewObject();
        // 読み込み
        sp_new_object->zzf_setupData_by_File_
          ( ptr_chunk
          , in_ptr_d3d_dev
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );
        // テーブル追加
        m_object_sp_table.push_back( sp_new_object );
        // ルート判定
        if( m_wp_object_root.lock() == nullptr )
        {
          m_wp_object_root = sp_new_object;
        }
      }
      //********** シェーダ **********//
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_SHADER ) )
      {
        // シェーダオブジェクト作成
        auto sp_shader = On_NewShader();
        // 読み込み
        sp_shader->zzf_setupData_by_File_
          ( in_ptr_d3d_dev
          , ptr_chunk
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );
        // テーブル追加
        m_shader_sp_table.push_back( sp_shader );
      }
      //********** テクスチャ **********//
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_TEXINFO ) )
      {
        // テクスチャオブジェクトの作成
        auto sp_texture = On_NewTexture();
        // 読み込み
        // ※ 共通テクスチャと組み込みテクスチャは自動で処理される
        sp_texture->zzf_setupData_by_File_
          ( ptr_chunk
          , in_ptr_d3d_dev
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          , this->m_path
          );
        // テーブル追加
        m_texture_sp_table.push_back( sp_texture );
      }
      //********** マテリアル **********//
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_CLRMTRL ) )
      {
        // カラーマテリアルの作成
        auto sp_clr_mtrl = On_NewColorMaterial();
        // 読み込み
        sp_clr_mtrl->zzf_setupData_by_File_
          ( ptr_chunk
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );
        // カラーマテリアルテーブルに追加
        m_color_material_sp_table.push_back( sp_clr_mtrl );
      }
      //********** ライト **********//
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_LITMTRL ) )
      {
        // ライトマテリアルの作成
        auto sp_light = On_NewLightMaterial();
        // 読み込み
        sp_light->zzf_setupData_by_File_
          ( ptr_chunk
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );
        // テーブル追加
        m_light_material_sp_table.push_back( sp_light );
      }
      //********** アニメ **********//
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_ANMDATA ) )
      {
        // アニメ作成
        auto sp_anm = On_NewAnimation();
        // ファイル読み込み
        sp_anm->zzf_setupData_by_File_
          ( ptr_chunk
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );
        // アニメテーブルに追加
        m_anime_sp_table.push_back( sp_anm );
      }
      else
      {
        On_OtherChunk( ptr_chunk, io_table_for_data_pointer );
      }

      // 
      ptr_data_addr += ptr_chunk->m_size;
    }
  }
  catch( ... )
  {
    Release();
    throw;
  }
};


// _____________________________________________________________________________
// 親子関係や、関連付けデータの設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::zzf_setupRelation_
    ( rio<Array_DataSPtr> io_table_for_data_pointer
    , rio<Array_ChunkPtr> io_table_for_chunk_pointer
    )
{
  // オブジェクト
  //CPL_LOOP2( m_object_sp_table.GetNum(), i )
  for( auto& sp_object : m_object_sp_table )
  {
    sp_object->zzf_setupRelation_
      ( io_table_for_data_pointer
      , io_table_for_chunk_pointer
      );
  }
//  // テクスチャ
//  int tex_num = m_texture_sp_table.GetNum();
//  for( int i = 0; i < tex_num; ++i )
//  {
//    m_texture_sp_table[ i ]->zzf_setupRelation_( io_table_for_data_pointer );
//  }
  // マテリアル
  //CPL_LOOP2( m_color_material_sp_table.GetNum(), i )
  for( auto& sp_color_material : m_color_material_sp_table )
  {
    sp_color_material->zzf_setupRelation_
      ( io_table_for_data_pointer
      , io_table_for_chunk_pointer
      );
  }
  // ライト
//  int light_num = m_light_material_sp_table.GetNum();
//  for( int i = 0; i < light_num; ++i )
//  {
//    m_light_material_sp_table[ i ]->zzf_setupRelation_( io_table_for_data_pointer );
//  }
  // アニメーション
  //CPL_LOOP2( m_anime_sp_table.GetNum(), i )
  for( auto& sp_anime : m_anime_sp_table )
  {
    sp_anime->zzf_setupRelation_
      ( io_table_for_data_pointer
      , io_table_for_chunk_pointer
      );
  }

  // シェーダー
  //CPL_LOOP2( m_shader_sp_table.GetNum(), i )
  for( auto& sp_shader : m_shader_sp_table )
  {
    sp_shader->zzf_setupRelation_
      ( io_table_for_data_pointer
      , io_table_for_chunk_pointer
      , this->m_light_material_sp_table
      );
  }
}


// _____________________________________________________________________________
// キーリストへのリンクの切り離し
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::zzf_clearRelation_()
{
  // オブジェクト
  for( auto& sp_object : m_object_sp_table )
  {
    sp_object->zzf_clearRelation_();
  }
  // マテリアル
  for( auto& sp_color_material : m_color_material_sp_table )
  {
    for
      ( int mtrl_param_idx = 0
      ; mtrl_param_idx < MeshFileInfo::kCOLOR_MTRL_PARAM_NUM
      ; ++mtrl_param_idx
      )
    {
      sp_color_material->m_wp_relation_keylist_color[ mtrl_param_idx ].reset();
    }
  }
  // ライト
//  int light_num = m_light_material_sp_table.GetNum();
//  for( int i = 0; i < light_num; ++i )
//  {
//    m_light_material_sp_table[ i ]->zzf_setupRelation_( io_table_for_data_pointer );
//  }
}


// _____________________________________________________________________________
// ソート済みオブジェクトテーブルを取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::zzf_getZSortObject_
    ( rout<Array_SpObject> out_object_table
    , _in <CVector3      > in_position_for_eye
    )
{
  out_object_table.clear();
  out_object_table.reserve( 16 );

  sdptr<Object> sp_object = m_wp_object_root.lock();
  std::vector< float > range_table; // カメラからオブジェクトまでの距離を保存

  // オブジェクトポインタテーブルの構築
  while( sp_object )
  {
    CVector3 pos = sp_object->m_vec_pos - in_position_for_eye;
    float len = Math::D3<float>::GetVecLength( pos );

    out_object_table.push_back( sp_object );
    range_table.push_back( len );

    if( sp_object->GetLinkChild() )
    {
      sp_object = sp_object->GetLinkChild();
    }
    else
    if( sp_object->GetLinkNext() )
    {
      sp_object = sp_object->GetLinkNext();
    }
    else
    {
      while( sp_object )
      {
        if( sp_object->GetLinkParent()  &&
            sp_object->GetLinkParent()->GetLinkNext() )
        {
          sp_object = sp_object->GetLinkParent()->GetLinkNext();
          break;
        }
        sp_object = sp_object->GetLinkParent();
      }
    }
  }

  // ソート（それほど個数は増えないと思われるので、単純な挿入ソートで。）
  size_t object_num = out_object_table.size();
  CPL_LOOP2( object_num, object_index_A )
  {
    for( size_t object_index_B = object_index_A + 1;
         object_index_B < object_num;
         ++object_index_B )
    {
      if( range_table[ object_index_A ] < range_table[ object_index_B ] )
      {
        Swap( out_object_table[ object_index_A ]
            , out_object_table[ object_index_B ]
            );
        Swap( range_table[ object_index_A ]
            , range_table[ object_index_B ]
            );
      }
    }
  }
}



// _____________________________________________________________________________
/// @brief 解放処理
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::Release()
{
  m_object_sp_table.clear();
  m_texture_sp_table.clear();
  m_light_material_sp_table.clear();
//  m_anime_sp_table.Release();
}

/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// アニメーションの設定　※ インデックス指定バージョン
// 戻り値 ： 成功(true)　失敗(false)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::SetAnimation_by_Index( int in_index )
{
  if( m_anime_sp_table )
  {
    this->zzf_clearRelation_();
    m_anime_sp_table->SetActiveAnimation_by_Index( in_index );
    return m_anime_sp_table->SetRelation( in_index, this );
  }
  else
  {
    return 0;
  }
}*/

/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// アニメーションの設定　※ ID指定バージョン
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::SetAnimation_by_UserID( int in_user_ID )
{
  if( m_anime_sp_table )
  {
    return m_anime_sp_table->SetRelation(
      m_anime_sp_table->ID_to_Index( in_user_ID ), this );
  }
  else
  {
    return 0;
  }
}*/

// _____________________________________________________________________________
/// @brief メッシュの描画
/// 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Draw
    ( _in<DX::DXDeviceContext*> in_ptr_d3d_emd_ctx
    , pin<CMatrix             > in_ptr_mtx_view_proj
    , pin<CMatrix             > in_ptr_mtx_proj
    , pin<CMatrix             > in_ptr_mtx_view
    , _in<CVector3            > in_position_for_eye
    , _in<CVector3            > in_look_pos
    )
{
  // ライトデータテーブルの作成
  size_t light_num =
    this->m_light_material_sp_table.size();
  Core::Array::Constant<float4>   light_color ( light_num );
  Core::Array::Constant<CVector3> light_pos   ( light_num );
  Core::Array::Constant<CVector3> light_normal( light_num );
  Core::Array::Constant<float>    light_power ( light_num );
  CPL_LOOP2( light_num, idx )
  {
    light_color [ idx ] = m_light_material_sp_table[ idx ]->m_color;
    light_pos   [ idx ] = m_light_material_sp_table[ idx ]->m_vec_pos;
    light_power [ idx ] = m_light_material_sp_table[ idx ]->m_power;
    light_normal[ idx ] = CVector3(0,1,0);
    Math::D3<float>::GetVecRotXrad
      ( light_normal[ idx ]
      , m_light_material_sp_table[ idx ]->m_vec_rot.x
      );
    Math::D3<float>::GetVecRotZrad
      ( light_normal[ idx ]
      , m_light_material_sp_table[ idx ]->m_vec_rot.z
      );
    Math::D3<float>::GetVecRotYrad
      ( light_normal[ idx ]
      , m_light_material_sp_table[ idx ]->m_vec_rot.y
      );
  }
  // ライトポインタ設定
  LightDataTable light_table; // ライト情報のポインタテーブルクラス
  light_table.m_light_num        = light_num;
  light_table.m_ptr_color_table  = &light_color;
  light_table.m_ptr_pos_table    = &light_pos;
  light_table.m_ptr_normal_table = &light_normal;
  light_table.m_ptr_power_table  = &light_power;

  // テクスチャポインタテーブル設定
  Array_TexData tex_table;
  //CPL_LOOP2( m_texture_sp_table.GetNum(), i )
  for( auto& sp_texture : m_texture_sp_table )
  {
    tex_table.push_back( sp_texture->m_ptr_texture );
  }

  //
  Array_SpObject object_table;
  zzf_getZSortObject_( object_table, in_position_for_eye );

  // 
  auto sp_anime = this->GetActiveAnimation();
//  float frame = sp_anime ? sp_anime->GetPlayIndex() : 0;
  // マトリクス更新
  size_t object_num = object_table.size();
  CPL_LOOP2( object_num, i )
  {
    object_table[ i ]->UpdateMatrix( nullptr, true );
  }
  // 描画準備
  MeshData::DrawObjectDesc dod;
  dod.m_ptr_d3d_emd_ctx   = in_ptr_d3d_emd_ctx;
  dod.m_ptr_eye_pos       = &in_position_for_eye;
  dod.m_ptr_look_pos      = &in_look_pos;
  dod.m_ptr_mtx_view_proj = in_ptr_mtx_view_proj;
  dod.m_ptr_mtx_proj      = in_ptr_mtx_proj;
  dod.m_ptr_mtx_view      = in_ptr_mtx_view;
  dod.m_ptr_light_table   = &light_table;
  dod.m_ptr_tex_table     = &tex_table;
  // 描画
  CPL_LOOP2( object_num, idx )
  {
    object_table[ idx ]->Draw( dod );
  }
}


// _____________________________________________________________________________
/// @brief オブジェクト作成
/// 
/// @copydetails doxycomment::arg_in_sp_object_for_parent
/// 
/// @return 作成したオブジェクト（スマートポインタ）を返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::Object>
  MeshData::CreateObject( _in<sdptr<Object>> in_sp_object_for_parent )
{
  // 新規オブジェクトを取得
  auto sp_new_object = On_NewObject();
  if( !sp_new_object )
  {
    return nullptr;
  }

  // テーブル追加
  m_object_sp_table.push_back( sp_new_object );

  // 
  in_sp_object_for_parent->AddLinkChild( sp_new_object );

  return sp_new_object;
}


// _____________________________________________________________________________
/// @brief アニメーションの作成
/// 
/// @param[in] in_name_for_animation : アニメーションの名前を指定します。
/// @param[in] in_user_ID  : ユーザーIDを指定します。
/// 
/// @return 作成したアニメオブジェクトを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmData>
  MeshData::CreateAnimation
    ( _in<Core::StringA> in_name_for_animation
    , _in<U32          > in_user_ID
    )
{
  // 新規アニメーションを取得
  auto sp_new_anime = On_NewAnimation();
  if( !sp_new_anime )
  {
    return nullptr;
  }
  sp_new_anime->SetName( in_name_for_animation );
  sp_new_anime->SetUserID( in_user_ID );

  // テーブルに追加
  m_anime_sp_table.push_back( sp_new_anime );

  return sp_new_anime;
}


// _____________________________________________________________________________
/// @brief カラーマテリアルの作成
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::ColorMaterial>
  MeshData::CreateColorMaterial()
{
  // 新規カラーマテリアルの取得
  auto sp_new_color_mtrl = On_NewColorMaterial();
  if( !sp_new_color_mtrl )
  {
    return nullptr;
  }

  // テーブルに追加
  m_color_material_sp_table.push_back( sp_new_color_mtrl );

  return sp_new_color_mtrl;
}


// _____________________________________________________________________________
/// @brief ライトマテリアルの作成
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::LightMaterial>
  MeshData::CreateLightMaterial()
{
  // 新規ライトマテリアルの取得
  auto sp_new_light_mtrl = On_NewLightMaterial();
  if( !sp_new_light_mtrl )
  {
    return nullptr;
  }

  // テーブルに追加
  m_light_material_sp_table.push_back( sp_new_light_mtrl );

  return sp_new_light_mtrl;
}


// _____________________________________________________________________________
/// @brief シェーダーの作成
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::Shader>
  MeshData::CreateShader()
{
  // 新規シェーダーの取得
  auto sp_new_shader = On_NewShader();
  if( !sp_new_shader )
  {
    return nullptr;
  }

  // テーブルに追加
  m_shader_sp_table.push_back( sp_new_shader );

  return sp_new_shader;
}


// _____________________________________________________________________________
/// @brief テクスチャの作成
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::Texture>
  MeshData::CreateTexture()
{
  // 新規テクスチャの取得
  auto sp_new_texture = On_NewTexture();
  if( !sp_new_texture )
  {
    return nullptr;
  }

  // テーブルに追加
  m_texture_sp_table.push_back( sp_new_texture );

  return sp_new_texture;
}


// _____________________________________________________________________________
/// @brief テクスチャマテリアルの作成
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::TextureMaterial>
  MeshData::CreateTextureMaterial()
{
  // 新規テクスチャマテリアルの取得
  auto sp_new_tex_mtrl = On_NewTextureMaterial();
  if( !sp_new_tex_mtrl )
  {
    return nullptr;
  }

  // テーブルに追加
  m_texture_material_sp_table.push_back( sp_new_tex_mtrl );

  return sp_new_tex_mtrl;
}



// _____________________________________________________________________________
/// @brief オブジェクト追加
/// 
/// @param[in] in_sp_object
///   : 追加するオブジェクトを指すスマートポインタを指定します。
/// @copydetails doxycomment::arg_in_sp_object_for_parent
///   : nullptrを指定するとルート階層に追加されます。
/// 
/// @return 追加されたオブジェクトを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::Object>
  MeshData::AddObject
    ( _in<sdptr<Object>> in_sp_object
    , _in<sdptr<Object>> in_sp_object_for_parent
    )
{
  if( in_sp_object_for_parent )
  {
    return in_sp_object_for_parent->AddLinkChild( in_sp_object );
  }
  else
  {
    m_object_sp_table.push_back( in_sp_object );
    return in_sp_object;
  }
}


// _____________________________________________________________________________
/// @brief アニメーションの追加
/// 
/// @param[in] in_sp_animation
///   : 追加するアニメーションを指すスマートポインタを渡します。
/// @copydetails doxycomment::arg_in_insert_key_index
/// 
/// @return 追加されたアニメーションを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmData>
  MeshData::AddAnimation
    ( _in<sdptr<AnmData>> in_sp_animation
    , _in<int           > in_insert_key_index
    )
{
  if( FAILED_INDEX(in_insert_key_index) )
  {
    m_anime_sp_table.push_back( in_sp_animation );
  }
  else
  {
    m_anime_sp_table.insert
      ( m_anime_sp_table.begin() + in_insert_key_index
      , in_sp_animation
      );
  }

  return in_sp_animation;
}

// _____________________________________________________________________________
/// @brief カラーマテリアルの追加
/// 
/// @param[in] in_sp_material_of_color
///   : 追加するカラーマテリアルを指すスマートポインタを指定します。
/// @copydetails doxycomment::arg_in_insert_key_index
/// 
/// @return 追加されたカラーマテリアルを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::ColorMaterial>
  MeshData::AddColorMaterial
    ( _in<sdptr<ColorMaterial>> in_sp_material_of_color
    , _in<int                 > in_insert_key_index
    )
{
  if( FAILED_INDEX(in_insert_key_index) )
  {
    m_color_material_sp_table.push_back( in_sp_material_of_color );
  }
  else
  {
    m_color_material_sp_table.insert
      ( m_color_material_sp_table.begin() + in_insert_key_index
      , in_sp_material_of_color
      );
  }
  return in_sp_material_of_color;
}


// _____________________________________________________________________________
/// @brief ライトマテリアルの追加
/// 
/// @param[in] in_sp_material_of_light
///   : 追加するライトマテリアルを指すスマートポインタを渡します。
/// @copydetails doxycomment::arg_in_insert_key_index
/// 
/// @return 追加されたライトマテリアルを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::LightMaterial>
  MeshData::AddLightMaterial
    ( _in<sdptr<LightMaterial>> in_sp_material_of_light
    , _in<int                 > in_insert_key_index
    )
{
  if( FAILED_INDEX(in_insert_key_index) )
  {
    m_light_material_sp_table.push_back( in_sp_material_of_light );
  }
  else
  {
    m_light_material_sp_table.insert
      ( m_light_material_sp_table.begin() + in_insert_key_index
      , in_sp_material_of_light
      );
  }

  return in_sp_material_of_light;
}


// _____________________________________________________________________________
/// @brief シェーダーの追加
/// 
/// @param[in] in_sp_shader
///   : 追加するシェーダーを指すスマートポインタを渡します。
/// @copydetails doxycomment::arg_in_insert_key_index
/// 
/// @return 追加されたシェーダーを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::Shader>
  MeshData::AddShader
    ( _in<sdptr<Shader>> in_sp_shader
    , _in<int          > in_insert_key_index
    )
{
  if( FAILED_INDEX(in_insert_key_index) )
  {
    m_shader_sp_table.push_back( in_sp_shader );
  }
  else
  {
    m_shader_sp_table.insert
      ( m_shader_sp_table.begin() + in_insert_key_index
      , in_sp_shader
      );
  }

  return in_sp_shader;
}

// _____________________________________________________________________________
/// @brief テクスチャの追加
/// 
/// @param[in] in_sp_texture
///   : 追加するテクスチャを指すスマートポインタを渡します。
/// @copydetails doxycomment::arg_in_insert_key_index
/// 
/// @return 追加されたテクスチャを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::Texture>
  MeshData::AddTexture
    ( _in<sdptr<Texture>> in_sp_texture
    , _in<int           > in_insert_key_index
    )
{
  if( FAILED_INDEX(in_insert_key_index) )
  {
    m_texture_sp_table.push_back( in_sp_texture );
  }
  else
  {
    m_texture_sp_table.insert
      ( m_texture_sp_table.begin() + in_insert_key_index
      , in_sp_texture
      );
  }

  return in_sp_texture;
}


// _____________________________________________________________________________
/// @brief テクスチャマテリアルの追加
/// 
/// @param[in] in_sp_material_of_texture
///   : 追加するテクスチャマテリアルを指すスマートポインタを渡します。
/// @copydetails doxycomment::arg_in_insert_key_index
/// 
/// @return 追加されたテクスチャマテリアルを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::TextureMaterial>
  MeshData::AddTextureMaterial
    ( _in<sdptr<TextureMaterial>> in_sp_material_of_texture
    , _in<int                   > in_insert_key_index
    )
{
  if( FAILED_INDEX(in_insert_key_index) )
  {
    m_texture_material_sp_table.push_back( in_sp_material_of_texture );
  }
  else
  {
    m_texture_material_sp_table.insert
      ( m_texture_material_sp_table.begin() + in_insert_key_index
      , in_sp_material_of_texture
      );
  }

  return in_sp_material_of_texture;
}



namespace zzz_
{
  template<class T, class U>
  bool EraseIf( std::vector<T>& io_table, U& data )
  {
    auto itr_hit = std::find( io_table.begin(), io_table.end(), data );
    if( itr_hit != io_table.end() )
    {
      io_table.erase( itr_hit );
      return true;
    }
    return false;
  }
}


// _____________________________________________________________________________
/// @brief オブジェクトの削除
/// 
/// @param[in] in_sp_object
///   : 削除対象のオブジェクトを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::DeleteObject( _in<sdptr<Object>> in_sp_object )
{
  return zzz_::EraseIf( m_object_sp_table, in_sp_object );
}


// _____________________________________________________________________________
/// @brief アニメーションの削除
/// 
/// @param[in] in_sp_animation
///   : 削除対象のアニメーションを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::DeleteAnimation( _in<sdptr<AnmData>> in_sp_animation )
{
  return zzz_::EraseIf( m_anime_sp_table, in_sp_animation );
}


// _____________________________________________________________________________
/// @brief カラーマテリアルの削除（ポインタ指定version）
/// 
/// @param[in] in_sp_material_of_color
///   : 削除対象のオブジェクトを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  MeshData::DeleteColorMaterial
    ( _in<sdptr<ColorMaterial>> in_sp_material_of_color
    )
{
  return zzz_::EraseIf( m_color_material_sp_table, in_sp_material_of_color );
}


// _____________________________________________________________________________
/// @brief カラーマテリアルの削除（インデックス指定version）
/// 
/// @param[in] in_index_for_color_material
///   : 削除対象のカラーマテリアルの配列インデックスを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::DeleteColorMaterial( _in<size_t> in_index_for_color_material )
{
  auto res =
    m_color_material_sp_table.erase
      ( m_color_material_sp_table.begin() + in_index_for_color_material
      );
  return res != m_color_material_sp_table.end();
}


// _____________________________________________________________________________
/// @brief ライトマテリアルの削除（ポインタ指定version）
/// 
/// @param[in] in_sp_material_of_light
///   : 削除対象のライトマテリアルを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  MeshData::DeleteLightMaterial
    ( _in<sdptr<LightMaterial>> in_sp_material_of_light
    )
{
  return zzz_::EraseIf( m_light_material_sp_table, in_sp_material_of_light );
}


// _____________________________________________________________________________
/// @brief ライトマテリアルの削除（インデックス指定version）
/// 
/// @param[in] in_index_for_light_material
///   : 削除対象のライトマテリアルの配列インデックスを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::DeleteLightMaterial( _in<size_t> in_index_for_light_material )
{
  auto res =
    m_light_material_sp_table.erase
      ( m_light_material_sp_table.begin() + in_index_for_light_material
      );
  return res != m_light_material_sp_table.end();
}


// _____________________________________________________________________________
/// @brief シェーダーの削除（ポインタ指定version）
/// 
/// @param[in] in_sp_shader
///   : 削除対象のシェーダーを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::DeleteShader( _in<sdptr<Shader>> in_sp_shader )
{
  return zzz_::EraseIf( m_shader_sp_table, in_sp_shader );
}


// _____________________________________________________________________________
/// @brief シェーダーの削除（インデックス指定version）
/// 
/// @param[in] in_index_for_shader
///   : 削除対象のシェーダーの配列インデックスを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::DeleteShader( _in<size_t> in_index_for_shader )
{
  auto res =
    m_shader_sp_table.erase
      ( m_shader_sp_table.begin() + in_index_for_shader
      );
  return res != m_shader_sp_table.end();
}


// _____________________________________________________________________________
/// @brief テクスチャの削除（ポインタ指定version）
/// 
/// @param[in] in_sp_texture
///   : 削除対象のテクスチャを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::DeleteTexture( _in<sdptr<Texture>> in_sp_texture )
{
  return zzz_::EraseIf( m_texture_sp_table, in_sp_texture );
}


// _____________________________________________________________________________
/// @brief テクスチャの削除（インデックス指定version）
/// 
/// @param[in] in_index_for_texture
///   : 削除対象のテクスチャの配列インデックスを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::DeleteTexture( _in<size_t> in_index_for_texture )
{
  auto res =
    m_texture_sp_table.erase
      ( m_texture_sp_table.begin() + in_index_for_texture
      );
  return res != m_texture_sp_table.end();
}


// _____________________________________________________________________________
/// @brief テクスチャマテリアルの削除（ポインタ指定version）
/// 
/// @param[in] in_sp_material_of_texture
///   : 削除対象のテクスチャマテリアルを指すスマートポインタを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  MeshData::DeleteTextureMaterial
    ( _in<sdptr<TextureMaterial>> in_sp_material_of_texture
    )
{
  return zzz_::EraseIf( m_texture_material_sp_table, in_sp_material_of_texture );
}


// _____________________________________________________________________________
/// @brief テクスチャマテリアルの削除（インデックス指定version）
/// 
/// @param[in] in_index_for_texture_material
///   : 削除対象のテクスチャの配列インデックスを指定します。
/// 
/// @retval true  : 削除成功
/// @retval false : 削除失敗
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  MeshData::DeleteTextureMaterial
    ( _in<size_t> in_index_for_texture_material
    )
{
  auto res =
    m_texture_material_sp_table.erase
      ( m_texture_material_sp_table.begin() + in_index_for_texture_material
      );
  return res != m_texture_material_sp_table.end();
}



// _____________________________________________________________________________
/// @brief メッシュファイルの書き出し（まだ未対応）
/// 
/// @param[out] out_stream_for_memory
///   : 取得用のメモリストリームオブジェクトを渡します。
/// 
/// @retval true  : 書き出し成功。
/// @retval false : 書き出し失敗。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::CreateMeshFile( rout<Core::MemoryStream> out_stream_for_memory )
{
  return false;
}





// _____________________________________________________________________________
/// @brief アニメリストの解放
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::AnimeRelease()
{
  m_anime_sp_table.clear();
}


// _____________________________________________________________________________
/// @brief アニメとメッシュの関連付け
/// 
/// @param[in] in_index_for_animation
///   : 関連付けるアニメーションの配列インデックスを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MeshData::SetAnimeRelation( _in<size_t> in_index_for_animation )
{
  // インデックス検査
  size_t anm_num = m_anime_sp_table.size();
  if( anm_num <= in_index_for_animation )
  {
    return false;
  }

  m_anime_sp_table[ in_index_for_animation ]->SetRelation( m_wp_myself.lock() );

  return true;
}


// _____________________________________________________________________________
/// @brief IDからインデックスに変換
/// 
/// @param[in] in_user_ID : ユーザーID.
/// 
/// @return
/// ユーザーIDと一致するアニメーションのインデックスを返す。\n
/// ※ 該当するIDがなかった場合、-1(全ビットON)を返す。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
size_t MeshData::GetAnimeIndex_by_ID( _in<int> in_user_ID )
{
  //CPL_LOOP2( m_anime_sp_table.GetNum(), i )
  for
    ( size_t idx = 0, num = m_anime_sp_table.size()
    ; idx < num
    ; ++idx
    )
  {
    if( m_anime_sp_table[ idx ]->GetUserID() == in_user_ID )
    {
      return idx;
    }
  }

  return (size_t)-1L;
}


// _____________________________________________________________________________
/// @brief アクティブなアニメーションを設定
/// 
/// @param[in] in_index_for_animation
///   : アニメーションのインデックスを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmData>
  MeshData::SetActiveAnimation_by_Index( _in<size_t> in_index_for_animation )
{
  const size_t anm_num = m_anime_sp_table.size();

  if( in_index_for_animation < anm_num )
  {
    m_wp_active_anime = m_anime_sp_table[ in_index_for_animation ];
    return m_wp_active_anime.lock();
  }
  m_wp_active_anime.reset();

  return nullptr;
}


// _____________________________________________________________________________
/// @brief アクティブなアニメーションを設定　※ ユーザーID指定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmData>
  MeshData::SetActiveAnimation_by_UserID( _in<int> in_user_id )
{
  return SetActiveAnimation_by_Index( GetAnimeIndex_by_ID( in_user_id ) );
}


// _____________________________________________________________________________
/// @brief アクティブなアニメーションを設定　※ ポインタ指定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<MeshData::AnmData>
  MeshData::SetActiveAnimation_by_Pointer( _in<sdptr<AnmData>> in_sp_anime )
{
  m_wp_active_anime = in_sp_anime;

  return in_sp_anime;
}




} // namespace CDI
} // namespace CPL


