/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2009/X/X - 2016/12/22
/// 
/// @brief  メッシュ　オブジェクト関連
/// 
/// ****************************************************************************

#include "CPL_CDI_MeshData.h"

namespace CPL {
namespace CDI {


enum eCPL_MFI_SHADER_BUF_TYPE_INDEX {
  kMFI_SDRBUFIDX_MTX_PROJ_VIEW,
  kMFI_SDRBUFIDX_MTX_PROJ,
  kMFI_SDRBUFIDX_MTX_VIEW,
  kMFI_SDRBUFIDX_MTX_WORLD,
  kMFI_SDRBUFIDX_CAMERA_INFO,
  kMFI_SDRBUFIDX_MTRL_DATA,
  kMFI_SDRBUFIDX_LIGHT_DATA,
};


// _____________________________________________________________________________
/// @brief デフォルトコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::Object::Object()
  : m_sp_idx_buf    ( nullptr )
  , m_vtx_num       ( 0 )
  , m_poly_num      ( 0 )
  , m_flag_billboard( false )
  , m_flag_z_sort   ( false )
  , m_flag_lighting ( false )
{
  // マトリクス初期化
  size_t mtx_num = m_blend_matrix.GetNum();
  for( size_t i = 0; i < mtx_num; ++i )
  {
    m_blend_matrix[i].Identity();
  }

  //
  m_sp_buf_collection = CPL_MAKE_SHARED(DX::Buffer::Collection);
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::Object::Object( cref<Object> in_obj )
  : td_base( in_obj )
  , m_blend_matrix           { in_obj.m_blend_matrix            }
  , m_bone_sp_table          { in_obj.m_bone_sp_table           }
  , m_tcs_sp_table           { in_obj.m_tcs_sp_table            }
  , m_sp_buf_collection      { in_obj.m_sp_buf_collection       }
  , m_sp_layout_buf          { in_obj.m_sp_layout_buf           }
  , m_sp_idx_buf             { in_obj.m_sp_idx_buf              }
  , m_sp_render_collection   { in_obj.m_sp_render_collection    }
  , m_vec_pos                { in_obj.m_vec_pos                 }
  , m_vec_rot                { in_obj.m_vec_rot                 }
  , m_vec_scl                { in_obj.m_vec_scl                 }
  , m_vtx_num                { in_obj.m_vtx_num                 }
  , m_poly_num               { in_obj.m_poly_num                }
  , m_flag_billboard         { in_obj.m_flag_billboard          }
  , m_flag_z_sort            { in_obj.m_flag_z_sort             }
  , m_flag_lighting          { in_obj.m_flag_lighting           }
  , m_flag_view              { in_obj.m_flag_view               }
  , m_wp_bone_root           { in_obj.m_wp_bone_root            }
  , m_wp_mirror_object       { in_obj.m_wp_mirror_object        }
  , m_sp_mirror_context      { in_obj.m_sp_mirror_context       }
  , m_wp_relation_texcoordset{ in_obj.m_wp_relation_texcoordset }
  , m_wp_relation_material   { in_obj.m_wp_relation_material    }
  , m_wp_relation_keylist_pos{ in_obj.m_wp_relation_keylist_pos }
  , m_wp_relation_keylist_rot{ in_obj.m_wp_relation_keylist_rot }
  , m_wp_relation_keylist_scl{ in_obj.m_wp_relation_keylist_scl }
  , m_wp_relation_shader     { in_obj.m_wp_relation_shader      }
{
  memcpy( m_tex_index, in_obj.m_tex_index, sizeof(m_tex_index) );
  memcpy( m_tex_blend, in_obj.m_tex_blend, sizeof(m_tex_blend) );
}

// _____________________________________________________________________________
/// @brief ムーブコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::Object::Object( rvref<Object> in_obj )
  : td_base( std::move(in_obj) )
  , m_blend_matrix           { std::move(in_obj.m_blend_matrix           ) }
  , m_bone_sp_table          { std::move(in_obj.m_bone_sp_table          ) }
  , m_tcs_sp_table           { std::move(in_obj.m_tcs_sp_table           ) }
  , m_sp_buf_collection      { std::move(in_obj.m_sp_buf_collection      ) }
  , m_sp_layout_buf          { std::move(in_obj.m_sp_layout_buf          ) }
  , m_sp_idx_buf             { std::move(in_obj.m_sp_idx_buf             ) }
  , m_sp_render_collection   { std::move(in_obj.m_sp_render_collection   ) }
  , m_vec_pos                { std::move(in_obj.m_vec_pos                ) }
  , m_vec_rot                { std::move(in_obj.m_vec_rot                ) }
  , m_vec_scl                { std::move(in_obj.m_vec_scl                ) }
  , m_vtx_num                { std::move(in_obj.m_vtx_num                ) }
  , m_poly_num               { std::move(in_obj.m_poly_num               ) }
  , m_flag_billboard         { std::move(in_obj.m_flag_billboard         ) }
  , m_flag_z_sort            { std::move(in_obj.m_flag_z_sort            ) }
  , m_flag_lighting          { std::move(in_obj.m_flag_lighting          ) }
  , m_flag_view              { std::move(in_obj.m_flag_view              ) }
  , m_wp_bone_root           { std::move(in_obj.m_wp_bone_root           ) }
  , m_wp_mirror_object       { std::move(in_obj.m_wp_mirror_object       ) }
  , m_sp_mirror_context      { std::move(in_obj.m_sp_mirror_context      ) }
  , m_wp_relation_texcoordset{ std::move(in_obj.m_wp_relation_texcoordset) }
  , m_wp_relation_material   { std::move(in_obj.m_wp_relation_material   ) }
  , m_wp_relation_keylist_pos{ std::move(in_obj.m_wp_relation_keylist_pos) }
  , m_wp_relation_keylist_rot{ std::move(in_obj.m_wp_relation_keylist_rot) }
  , m_wp_relation_keylist_scl{ std::move(in_obj.m_wp_relation_keylist_scl) }
  , m_wp_relation_shader     { std::move(in_obj.m_wp_relation_shader     ) }
{
  memcpy( m_tex_index, in_obj.m_tex_index, sizeof(m_tex_index) );
  memcpy( m_tex_blend, in_obj.m_tex_blend, sizeof(m_tex_blend) );
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ファイル読み込み処理
// ※ ストリームの内訳
//    0 : xyz | w | bw | bi | normal | psize
//    1 : diffuse | specular | emissive
//    2 : texcoord(1-4)
//    3 : other
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::zzf_setupData_by_File_
    ( pin<MeshFileInfo::Chunk> in_ptr_chunk
    , _in<DX::DXDevice*      > in_ptr_d3d_dev
    , rio<Array_DataSPtr     > io_table_for_data_pointer
    , rio<Array_ChunkPtr     > io_table_for_chunk_pointer
    )
{
  try {
    HRESULT hr = S_OK;

    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_Object const* ptr_info_object =
      reinterpret_cast<MFI_Object const*>(ptr_data_addr); // 情報にキャスト

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

    // プライベートデータの設定
    this->m_vec_pos = ptr_info_object->m_vec_pos;
    this->m_vec_rot = ptr_info_object->m_vec_rot;
    this->m_vec_scl = ptr_info_object->m_vec_scl;
    this->m_vtx_num = ptr_info_object->m_vtx_num;
    // クリア
    m_sp_buf_collection->Release();

    // チャンク部分までポインタを進める
    ptr_data_addr += sizeof(MFI_Object);

    // チャンクループ
    while( ptr_data_addr < ptr_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_VTXSTM ) ) // 頂点データ
      {
        // 頂点ストリーム情報へのポインタ
        MFI_VertexStreamData const*
          ptr_MFI_VSD = static_cast<MFI_VertexStreamData const*>(ptr_chunk);

        // 頂点ストリームバッファの作成
        sdptr<DX::Buffer::Interface_>
          sp_vse =
            CPL_MAKE_SHARED
              ( DX::Buffer::DynamicEX_Vertex
              , ptr_MFI_VSD->m_vtx_size
              , ptr_MFI_VSD->m_buf_size / ptr_MFI_VSD->m_vtx_size
              , ptr_MFI_VSD->DataAddr_()
              );
        // 頂点ストリームバッファの登録
        m_sp_buf_collection->EntryBuffer( sp_vse );

        // データポインタ登録
        io_table_for_data_pointer.Add( ptr_MFI_VSD->m_GID, sp_vse );
        // チャンクポインタ登録
        io_table_for_chunk_pointer.Add( sp_vse.get(), ptr_MFI_VSD );
      }
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_POLYGON ) ) // インデックス
      {
        MFI_Polygon const* ptr_poly_info =
          reinterpret_cast<MFI_Polygon const*>(ptr_data_addr);

        m_poly_num = ptr_poly_info->m_poly_num;

        if( m_poly_num > 0 )
        {
          // インデックスバッファの作成
          m_sp_idx_buf =
            CPL_MAKE_SHARED
              ( DX::Buffer::DynamicEX_Index
              , sizeof(int)
              , m_poly_num * 3
              , ptr_poly_info->DataAddr_()
              );

          // エラー判定
          CPL_THROW_CODE_IF2
            ( FAILED(hr)
            , (int)eErrorCode::NotCreateIndexBuffer
            , "インデックスバッファの作成に失敗\n"
            );
        }
      }
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_BONEDATA ) ) // ボーン
      {
        // ボーン作成
        auto sp_bone = On_NewBone();
        // 読み込み
        sp_bone->zzf_setupData_by_File_
          ( ptr_chunk
          , io_table_for_data_pointer
          , io_table_for_chunk_pointer
          );
        // ルート判定
        if( m_wp_bone_root.expired() ) // 設定されていない場合。
        {
          m_wp_bone_root = sp_bone; // ルートボーン設定
        }
        // テーブル追加
        m_bone_sp_table.AddEnd( sp_bone );
      }
      else
      if( ptr_chunk->IsType( CPL_MFI_CHUNK_TEXCDSET ) ) // テクスチャ座標セット
      {
        // テクスチャ座標セット作成
        auto sp_texcoord = On_NewTexCoordSet();
        // 読み込み
        sp_texcoord->
          zzf_setupData_by_File_
            ( ptr_chunk
            , in_ptr_d3d_dev
            , io_table_for_data_pointer
            , io_table_for_chunk_pointer
            , m_vtx_num
            );
        // テーブル追加
        m_tcs_sp_table.AddEnd( sp_texcoord );
      }

      ptr_data_addr += ptr_chunk->m_size;
    }

  }
//  catch( std::exception& exc )
  catch( ... )
  {
    Release();

    throw;
  }
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Core4D Object 関連付けデータの設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::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 );
  MFI_Object const*
    ptr_info_object =
      static_cast<MFI_Object const*>(*pp_chunk_info);

  // ボーン
  size_t bone_num = m_bone_sp_table.GetNum();
  for( size_t i = 0; i < bone_num; ++i )
  {
    m_bone_sp_table[ i ]->zzf_setupRelation_
      ( io_table_for_data_pointer
      , io_table_for_chunk_pointer
      );
  }
//  // 頂点グループ
//  int vtx_grp_num = m_pVtxGrpTable.GetNum();
//  for( int i = 0; i < vtx_grp_num; ++i ){
//    m_pVtxGrpTable[ i ]->zzf_setupRelation_( io_table_for_data_pointer );
//  }
//  // テクスチャ座標セット
//  int tcs_num = m_pm_pTexCoordTable.GetNum();
//  for( int i = 0; i < tcs_num; ++i ){
//    m_tcs_sp_table[ i ]->zzf_setupRelation_( io_table_for_data_pointer );
//  }

  void_sptr* psp_data;
  // 次のオブジェクトの設定
  psp_data = io_table_for_data_pointer.Find( ptr_info_object->m_GID_next );
  if( psp_data )
  {
    sdptr<Object> sp_object_next = std::static_pointer_cast<Object>(*psp_data);
    this->AddLinkNext( sp_object_next );
  }

  // 子供オブジェクトの設定
  psp_data = io_table_for_data_pointer.Find( ptr_info_object->m_GID_child );
  if( psp_data )
  {
    sdptr<Object> sp_object_child = std::static_pointer_cast<Object>(*psp_data);
    this->AddLinkChild( sp_object_child );
  }

  // マテリアル
  psp_data = io_table_for_data_pointer.Find( ptr_info_object->m_GID_material );
  m_wp_relation_material =
    psp_data ? std::static_pointer_cast<ColorMaterial>(*psp_data)
             : nullptr;

  // ミラーオブジェクト設定
  psp_data = io_table_for_data_pointer.Find( ptr_info_object->m_GID_mirror );
  m_wp_mirror_object =
    psp_data ? std::static_pointer_cast<Object>(*psp_data)
             : nullptr;

  // ↓のキーリストはアニメーションで関連付けられる
//  // 座標キーリスト
//  m_wp_relation_keylist_pos = io_table_for_data_pointer.Find( in_ptr_info_object->m_GID_keylist_pos );
//  // 角度キーリスト
//  m_wp_relation_keylist_rot = io_table_for_data_pointer.Find( in_ptr_info_object->m_GID_keylist_rot );
//  // 拡縮キーリスト
//  m_wp_relation_keylist_scl = io_table_for_data_pointer.Find( in_ptr_info_object->m_GID_keylist_scl );

  // シェーダ関連付け
  psp_data = io_table_for_data_pointer.Find( ptr_info_object->m_GID_shader );
  m_wp_relation_shader =
    psp_data ? std::static_pointer_cast<Shader>(*psp_data)
             : nullptr;

  // 頂点バッファと頂点レイアウトの関連付け
  // 頂点宣言オブジェクトを取得
  psp_data = io_table_for_data_pointer.Find( ptr_info_object->m_GID_declaration );
  //DX::Layout::Buffer::SpRefCnt sp_buf_layout;
  if( psp_data  &&  *psp_data )
  {
    auto
      sp_layout_buf =
        std::static_pointer_cast<MeshData::LayoutBuffer>(*psp_data);
    m_sp_layout_buf = sp_layout_buf->GetLayoutBuffer();
  }
  else
  {
    m_sp_layout_buf = nullptr;
  }
//  if( m_vtx_num > 0 )
//  {
//    //***** メモリに配置される頂点バッファの情報を作成 *****//
//    // 頂点シェーダ宣言を取得
//    D3DVERTEXELEMENT9 decl[256];
//    UINT              num_elements;
//    m_wp_relation_shader->GetDeclaration()->GetDeclaration( decl, &num_elements );
//    //// データオフセット初期化
//    //for( int i = 0; i < MeshFileInfo::VF_NUM; ++i )
//    //{
//    //  m_vtx_data_offs[ i ] = (U8)-1;
//    //}
//    //// 頂点サイズテーブルの初期化
//    //int tmp_vtx_size[ MeshFileInfo::VSI_NUM ] = { 0 };
//    //for( int i = 0; i < MeshFileInfo::VSI_NUM; ++i )
//    //{
//    //  tmp_vtx_size[ i ] = 0;
//    //}
//    // 
//    //int  mem_fmt_num = static_cast<int>(num_elements) - 1;
//    //for( int i = 0; i < mem_fmt_num; ++i )
//    //{
//    //  const DX::BaseElement::VTX_TYPE_IDformat =
//    //    DX::BaseElement::GetFormat_by_Element( decl[i] );
//    //  const int stream = decl[i].Stream;
//
//    //  m_vtx_data_offs[ format ] = tmp_vtx_size[ stream ];
//    //  tmp_vtx_size[ stream ] += MeshFileInfo::GetFormatSize( format );
//    //}
//
//    // フォーマット検査しながら、一時バッファに書き込み（これにより、全体のサイズも求まる）
//    MemoryStream tmp_vtx_buf[ MeshFileInfo::VSI_NUM ];
////    int sdr_fmt_num = static_cast<int>(ptr_shader->m_ptr_info_shader->m_format_num); // シェーダー宣言のフォーマット数
//    char_cptr ptr_vtx_data_addr =
//      static_cast<char_cptr>(ptr_vtx_list->DataAddr_());    // 参照データのアドレス
//    int src_vtx_size = ptr_vtx_list->m_vtx_size;
//    //
//    for( U32 i = 0; i < m_vtx_num; ++i )
//    {
//      for( int fmt_tbl_idx = 0; fmt_tbl_idx < mem_fmt_num; ++fmt_tbl_idx )
//      {
//        int format = MeshFileInfo::GetFormat_by_Element( decl[fmt_tbl_idx] );   // フォーマットタイプ
//        int stream = data_stream_idx[ format ];
////      if( stream == 0 )
////      {
//          int offset = src_fmt_offs[ format ]; // 参照データの指定フォーマットのオフセット
//          int size   = MeshFileInfo::GetFormatSize( format ); // 指定フォーマットのサイズ
//          if( offset >= 0 ) // オフセットが無い場合は、ソースにデータなし
//          {
//            tmp_vtx_buf[ stream ].Write( ptr_vtx_data_addr + offset, size );
//          }
//          else
//          {
//            char dummy[ 256 ] = { 0 };
//            tmp_vtx_buf[ stream ].Write( dummy, size ); // ダミーの値を書き込み（後に設定する）
//          }
////      }
//      }
//
//      ptr_vtx_data_addr += src_vtx_size;
//    }
//    // 参照データに無いデータの設定
//    for( int format = 0; format < MeshFileInfo::VF_NUM; ++format )
//    {
//      if( format == MeshFileInfo::VF_NORMAL  &&  src_fmt_offs[ format ] < 0 ) // 法線データが無い場合
//      {
//        // 今のところ法線のみ対応
//        //***** 法線データを自動計算する *****//
//        int normal_offset = -1;
//        for( int decl_idx = 0; decl_idx < (int)num_elements; ++decl_idx )
//        {
//          if( decl[ decl_idx ].Usage == D3DDECLUSAGE_NORMAL )
//          {
//            normal_offset = decl[ decl_idx ].Offset;
//          }
//        }
//        if( normal_offset >= 0 )
//        {
//          Array::Constant<float3> tmp_normal( m_vtx_num, float3(0,0,0) ); // xyz：座標　w：カウント
//          ptr_vtx_data_addr = static_cast<char_cptr>(ptr_vtx_list->DataAddr_());
//          CVector3 vtx[ 3 ];
//          D3DINDEXBUFFER_DESC desc;
//          this->m_sp_idx_buf->GetDesc( &desc );
//          int is_index16 = (desc.Format == D3DFMT_INDEX16);
//          int index_num = this->m_poly_num * 3;
//          int idx0, idx1, idx2;
//          DX::AutoLockIB<U16> ib( this->m_sp_idx_buf );
//          U16* ptr_index16 = ib;
//          U32* ptr_index32 = reinterpret_cast<U32*>(ptr_index16);
//          for( int idx = 0; idx < index_num; idx += 3 )
//          {
//            // インデックス取得
//            if( is_index16 )
//            {
//              idx0 = ptr_index16[ idx   ];
//              idx1 = ptr_index16[ idx+1 ];
//              idx2 = ptr_index16[ idx+2 ];
//            }
//            else
//            {
//              idx0 = ptr_index32[ idx   ];
//              idx1 = ptr_index32[ idx+1 ];
//              idx2 = ptr_index32[ idx+2 ];
//            }
//            // ポリゴンの３点を取得
//            CVector3::cptr pVtx0 = reinterpret_cast<CVector3::cptr>(ptr_vtx_data_addr + src_vtx_size * idx0);
//            CVector3::cptr pVtx1 = reinterpret_cast<CVector3::cptr>(ptr_vtx_data_addr + src_vtx_size * idx1);
//            CVector3::cptr pVtx2 = reinterpret_cast<CVector3::cptr>(ptr_vtx_data_addr + src_vtx_size * idx2);
//            // 法線を求める
//            CVector3 poly_nor;
//            Math::D3<float>::GetNormal3p( poly_nor, *pVtx0, *pVtx1, *pVtx2 );
//            // 法線を加算していく
//            tmp_normal[ idx0 ] = float3( poly_nor.x, poly_nor.y, poly_nor.z );// tmp_normal[ idx0 ].w + 1 );
//            tmp_normal[ idx1 ] = float3( poly_nor.x, poly_nor.y, poly_nor.z );// tmp_normal[ idx1 ].w + 1 );
//            tmp_normal[ idx2 ] = float3( poly_nor.x, poly_nor.y, poly_nor.z );// tmp_normal[ idx2 ].w + 1 );
//          }
//          for( U32 vtx_idx = 0; vtx_idx < m_vtx_num; ++vtx_idx )
//          {
//            // 法線を正規化
//            Math::D3<float>::VecNormalize( &tmp_normal[ vtx_idx ].x );
//            char_ptr ptr_tmp_buf_addr = reinterpret_cast<char_ptr>(tmp_vtx_buf[ VSI_NORMAL ].GetTopAddr());
//            *reinterpret_cast<CVector3*>(ptr_tmp_buf_addr + m_vtx_size * vtx_idx + normal_offset)
//              = tmp_normal[ vtx_idx ];
//          }
//        }
//        break;
//      }
//    }
//
//    // 頂点バッファ作成
//    for( int stream_idx = 0; stream_idx < MeshFileInfo::VSI_NUM; ++i )
//    {
//      if( tmp_vtx_buf[ stream_idx ].GetSize() > 0 )
//      {
//        switch( stream_idx )
//        {
//          case MeshFileInfo::VSI_VECTOR:    m_ptr_vtx_buf[ stream_idx ] = new 
//          case MeshFileInfo::VSI_BLEND:
//          case MeshFileInfo::VSI_NORMAL:
//          case MeshFileInfo::VSI_COLOR:
//          case MeshFileInfo::VSI_TEXCOORD:
//          case MeshFileInfo::VSI_PSIZE:
//          case MeshFileInfo::VSI_DEPTH:
//          case MeshFileInfo::VSI_TANGENT:
//          case MeshFileInfo::VSI_BINORMAL:
//          case MeshFileInfo::VSI_TESSFACTOR:
//          case MeshFileInfo::VSI_FOG:
//        }
//
//        m_ptr_vtx_buf[ stream_idx ] = new 
//        HRESULT hr =
//          ptr_d3d_dev->CreateVertexBuffer(
//                        vtx_buf_size,
//                        0, 0, D3DPOOL_MANAGED,
//                        &m_ptr_vtx_buf, nullptr );
//        CPL_THROW_CODE_IF2(
//          FAILED(hr),
//          CEC_NOT_CREATE_VERTEX_BUFFER,
//          "頂点バッファの作成に失敗\n" );
//        
//        // データコピー
//        DX::AutoLockVB<char> vb( m_ptr_vtx_buf );
//        ::memcpy( vb, tmp_vtx_buf.GetTopAddr(), vtx_buf_size );
//      }
//    }
//
//    U32 vtx_buf_size = tmp_vtx_buf.GetSize();
//    HRESULT hr =
//      ptr_d3d_dev->CreateVertexBuffer(
//                    vtx_buf_size,
//                    0, 0, D3DPOOL_MANAGED,
//                    &m_ptr_vtx_buf, nullptr );
//    CPL_THROW_CODE_IF2(
//      FAILED(hr),
//      CEC_NOT_CREATE_VERTEX_BUFFER,
//      "頂点バッファの作成に失敗\n" );
//    // データ設定
//    DX::AutoLockVB<char> vb( m_ptr_vtx_buf );
//    ::memcpy( vb, tmp_vtx_buf.GetTopAddr(), vtx_buf_size );
//  }

//  in_ptr_info_object = nullptr; // ファイルデータへのポインタをクリア
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// キーリストへのリンクをクリア
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::Object::zzf_clearRelation_()
{
  m_wp_relation_texcoordset.reset();
  m_wp_relation_material   .reset();
  m_wp_relation_keylist_pos.reset();
  m_wp_relation_keylist_rot.reset();
  m_wp_relation_keylist_scl.reset();

  size_t bone_num = m_bone_sp_table.GetNum();
  for( size_t i = 0; i < bone_num; ++i )
  {
    m_bone_sp_table[ i ]->m_wp_relation_keylist_pos.reset();
    m_bone_sp_table[ i ]->m_wp_relation_keylist_rot.reset();
    m_bone_sp_table[ i ]->m_wp_relation_keylist_scl.reset();
  }

//  int vtx_grp_num = m_pVtxGrpTable.GetNum();
//  for( int i = 0; i < vtx_grp_num; ++i ){
//    m_pVtxGrpTable[ i ]->m_pRD_Bone = 0;
//  }
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// シェーダパラメータの更新
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::zzf_updateShaderData_
    ( _in<DrawObjectDesc> in_draw_obj_desc
    , pin<CMatrix       > in_ptr_mtx_bbr
    ) const
{
  if( m_wp_relation_shader.expired() )
  {
    return;
  }

  //// コード簡易化用
  //DrawObjectDesc const& dod = in_draw_obj_desc;
  //DX::DXDeviceContext* ptr_d3d_emd_ctx = dod.m_ptr_d3d_emd_ctx;
  //
  //// シェーダ
  //MeshFileInfo::Shader::VSInfo const&
  //  vs_info = m_wp_relation_shader.lock()->GetVS_Param();
  //MeshFileInfo::Shader::PSInfo const&
  //  ps_info = m_wp_relation_shader.lock()->GetPS_Param();

  // データ設定 **********
  /***** vertex shader *****/
  
  //int blend_matrix_num = this->m_bone_sp_table.GetNum() + 1;
  // view projection matrix
  //if( vs_info.GetUse( VSN_MTX_VIEW_PROJ ) )
  //{
  //  ptr_constant_table_vs->SetMatrix(
  //    ptr_d3d_dev,
  //    vs_info.GetName( VSN_MTX_VIEW_PROJ ),
  //    *dod.m_ptr_mtx_view_proj );
  //}
  //ptr_d3d_emd_ctx->VSSetConstantBuffers( 0, 1, &buf );
  //// projection matrix
  //if( vs_info.GetUse( VSN_MTX_PROJ ) )
  //{
  //  ptr_constant_table_vs->SetMatrix(
  //    ptr_d3d_dev,
  //    vs_info.GetName( VSN_MTX_PROJ ),
  //    *dod.m_ptr_mtx_proj );
  //}
  //// view matrix
  //if( vs_info.GetUse( VSN_MTX_VIEW ) )
  //{
  //  ptr_constant_table_vs->SetMatrix(
  //    ptr_d3d_dev,
  //    vs_info.GetName( VSN_MTX_VIEW ),
  //    *dod.m_ptr_mtx_view );
  //}
  //// world matrix
  //if( vs_info.GetUse( VSN_MTX_WORLD ) )
  //{
  //  ptr_constant_table_vs->SetMatrixArray(
  //    ptr_d3d_dev,
  //    vs_info.GetName( VSN_MTX_WORLD ),
  //    m_blend_matrix[0], blend_matrix_num );
  //}
  //// color material
  //if( m_sp_relation_material )
  //{
  //  // material color 0
  //  if( vs_info.GetUse( VSN_MTRL_PARAM0 ) )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      vs_info.GetName( VSN_MTRL_PARAM0 ),
  //      &m_sp_relation_material->m_color[0].x, 4 );
  //  }
  //  // material color 1
  //  if( vs_info.GetUse( VSN_MTRL_PARAM1 ) )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      vs_info.GetName( VSN_MTRL_PARAM1 ),
  //      &m_sp_relation_material->m_color[1].x, 4 );
  //  }
  //  // material color 2
  //  if( vs_info.GetUse( VSN_MTRL_PARAM2 ) )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      vs_info.GetName( VSN_MTRL_PARAM2 ),
  //      &m_sp_relation_material->m_color[2].x, 4 );
  //  }
  //  // material color 3
  //  if( vs_info.GetUse( VSN_MTRL_PARAM3 ) )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      vs_info.GetName( VSN_MTRL_PARAM3 ),
  //      &m_sp_relation_material->m_color[3].x, 4 );
  //  }
  //}
  //// eye position
  //if( vs_info.GetUse( VSN_EYE_POS ) )
  //{
  //  ptr_constant_table_vs->SetFloatArray(
  //    ptr_d3d_dev,
  //    vs_info.GetName( VSN_EYE_POS ),
  //    *dod.m_ptr_eye_pos, 3 );
  //}
  //// look position
  //if( vs_info.GetUse( VSN_LOOK_POS ) )
  //{
  //  ptr_constant_table_vs->SetFloatArray(
  //    ptr_d3d_dev,
  //    vs_info.GetName( VSN_LOOK_POS ),
  //    *dod.m_ptr_look_pos, 3 );
  //}
  //// billboard
  //if( m_flag_billboard  &&  in_ptr_mtx_bbr )
  //{
  //  ptr_constant_table_vs->SetMatrix(
  //    ptr_d3d_dev,
  //    "g_BillboardMtx",
  //    *in_ptr_mtx_bbr );
  //}


  //// ***** pixel shader ***** //
  //
  //// color material
  //if( m_sp_relation_material )
  //{
  //  // material color 0
  //  if( ps_info.GetUse( PSN_MTRL_PARAM0 ) )
  //  {
  //    ptr_constant_table_ps->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( PSN_MTRL_PARAM0 ),
  //      &m_sp_relation_material->m_color[0].x, 4 );
  //  }
  //  // material color 1
  //  if( ps_info.GetUse( PSN_MTRL_PARAM1 ) )
  //  {
  //    ptr_constant_table_ps->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( PSN_MTRL_PARAM1 ),
  //      &m_sp_relation_material->m_color[1].x, 4 );
  //  }
  //  // material color 2
  //  if( ps_info.GetUse( PSN_MTRL_PARAM2 ) )
  //  {
  //    ptr_constant_table_ps->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( PSN_MTRL_PARAM2 ),
  //      &m_sp_relation_material->m_color[2].x, 4 );
  //  }
  //  // material color 3
  //  if( ps_info.GetUse( PSN_MTRL_PARAM3 ) )
  //  {
  //    ptr_constant_table_ps->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( PSN_MTRL_PARAM3 ),
  //      &m_sp_relation_material->m_color[3].x, 4 );
  //  }
  //}
  //// eye position
  //if( ps_info.GetUse( PSN_EYE_POS )  &&  dod.m_ptr_eye_pos )
  //{
  //  ptr_constant_table_ps->SetFloatArray(
  //    ptr_d3d_dev,
  //    ps_info.GetName( PSN_EYE_POS ),
  //    *dod.m_ptr_eye_pos, 3 );
  //}
  //// look position
  //if( ps_info.GetUse( PSN_LOOK_POS )  &&  dod.m_ptr_look_pos )
  //{
  //  ptr_constant_table_ps->SetFloatArray(
  //    ptr_d3d_dev,
  //    ps_info.GetName( PSN_LOOK_POS ),
  //    *dod.m_ptr_look_pos, 3 );
  //}

  //// light
  //int light_num =
  //  dod.m_ptr_light_table ?
  //  dod.m_ptr_light_table->m_light_num - 1 : 0;
  //if( light_num > 0 )
  //{
  //  /***** vertex shader *****/
  //  
  //  // light ambient
  //  if( vs_info.GetUse( VSN_LIGHT_AMBIENT )  &&
  //      dod.m_ptr_light_table->m_ptr_color_table )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( VSN_LIGHT_AMBIENT ),
  //      (*dod.m_ptr_light_table->m_ptr_color_table)[0], 3 );
  //  }
  //  // light position
  //  if( vs_info.GetUse( VSN_LIGHT_POS )  &&
  //      dod.m_ptr_light_table->m_ptr_pos_table )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( VSN_LIGHT_POS ),
  //      (*dod.m_ptr_light_table->m_ptr_pos_table)[1], 3 * light_num );
  //  }
  //  // light normal
  //  if( vs_info.GetUse( VSN_LIGHT_NORMAL )  &&
  //      dod.m_ptr_light_table->m_ptr_normal_table )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( VSN_LIGHT_NORMAL ),
  //      (*dod.m_ptr_light_table->m_ptr_normal_table)[1], 3 * light_num );
  //  }
  //  // light power
  //  if( vs_info.GetUse( VSN_LIGHT_POWER )  &&
  //      dod.m_ptr_light_table->m_ptr_power_table )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( VSN_LIGHT_POWER ),
  //      &(*dod.m_ptr_light_table->m_ptr_power_table)[1], light_num );
  //  }

  //  /***** pixel shader *****/
  //  
  //  // light ambient
  //  if( ps_info.GetUse( PSN_LIGHT_AMBIENT )  &&
  //      dod.m_ptr_light_table->m_ptr_color_table )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( PSN_LIGHT_AMBIENT ),
  //      (*dod.m_ptr_light_table->m_ptr_color_table)[0], 3 );
  //  }
  //  // light position
  //  if( ps_info.GetUse( PSN_LIGHT_POS )  &&
  //      dod.m_ptr_light_table->m_ptr_power_table )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( PSN_LIGHT_POS ),
  //      &(*dod.m_ptr_light_table->m_ptr_power_table)[1], 3 * light_num );
  //  }
  //  // light normal
  //  if( ps_info.GetUse( PSN_LIGHT_NORMAL )  &&
  //      dod.m_ptr_light_table->m_ptr_normal_table )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( PSN_LIGHT_NORMAL ),
  //      (*dod.m_ptr_light_table->m_ptr_normal_table)[1], 3 * light_num );
  //  }
  //  // light power
  //  if( ps_info.GetUse( PSN_LIGHT_POWER )  &&
  //      dod.m_ptr_light_table->m_ptr_power_table )
  //  {
  //    ptr_constant_table_vs->SetFloatArray(
  //      ptr_d3d_dev,
  //      ps_info.GetName( PSN_LIGHT_POWER ),
  //      &(*dod.m_ptr_light_table->m_ptr_power_table)[1], light_num );
  //  }
  //}
}


// _____________________________________________________________________________
/// @brief ローカル座標の取得
/// 
/// @param[out] out_pos : 座標取得用のベクトルオブジェクトを渡します。
/// @copydetails doxycomment::arg_in_flag_interpolate
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::GetLocalPos
    ( rout<CVector3> out_pos
    , _in <bool    > in_flag_interpolate
    ) const
{
  if( auto sp_keylist = m_wp_relation_keylist_pos.lock() )
  {
    zzf_getKeyListVec( sp_keylist, in_flag_interpolate, out_pos );

    out_pos += m_vec_pos;
  }
  else
  {
    out_pos = m_vec_pos;
  }
}


// _____________________________________________________________________________
/// @brief ローカル角度の取得
/// 
/// @param[out] out_rot : 角度取得用のベクトルオブジェクトを渡します。
/// @copydetails doxycomment::arg_in_flag_interpolate
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::GetLocalRot
    ( rout<CVector3> out_rot
    , _in <bool    > in_flag_interpolate
    ) const
{
  if( auto sp_keylist = m_wp_relation_keylist_rot.lock() )
  {
    zzf_getKeyListVec( sp_keylist, in_flag_interpolate, out_rot );

    out_rot += m_vec_rot;
  }
  else
  {
    out_rot = m_vec_rot;
  }
}


// _____________________________________________________________________________
/// @brief ローカル倍率の取得
/// 
/// @param[out] out_scl : 倍率取得用のベクトルオブジェクトを渡します。
/// @copydetails doxycomment::arg_in_flag_interpolate
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::GetLocalScl
    ( rout<CVector3> out_scl
    , _in <bool    > in_flag_interpolate
    ) const
{
  if( auto sp_keylist = m_wp_relation_keylist_scl.lock() )
  {
    zzf_getKeyListVec( sp_keylist, in_flag_interpolate, out_scl );

    out_scl *= m_vec_scl;
  }
  else
  {
    out_scl = m_vec_scl;
  }
}


// _____________________________________________________________________________
/// @brief 後始末
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::Object::Release()
{
  m_wp_relation_material   .reset();
  m_wp_relation_keylist_pos.reset();
  m_wp_relation_keylist_rot.reset();
  m_wp_relation_keylist_scl.reset();

  m_bone_sp_table.Release();
//  m_pVtxGrpTable.Release();

//  RELEASE( m_ptr_vtx_buf );
//  RELEASE( m_sp_idx_buf );
}


// _____________________________________________________________________________
/// @brief 指定されたストリームの頂点バッファを取得
/// 
/// @param[in] in_index
///   : メッシュ用に定義されているバッファインデックスを指定します。\n
///   : 詳しくはeBufferIndexを参照してください。
/// 
/// @return
/// バッファオブジェクトを指すスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DX::Buffer::Interface_>
  MeshData::Object::GetBuffer_by_Index
    ( _in<eBufferIndex> in_index
    )
{
  return m_sp_buf_collection->GetBuffer_by_Index( static_cast<int>(in_index) );
}

// _____________________________________________________________________________
/// @copydoc MeshData::Object::GetBuffer_by_Index
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdcptr<DX::Buffer::Interface_>
  MeshData::Object::GetBuffer_by_Index
    ( _in<eBufferIndex> in_index
    ) const
{
  return m_sp_buf_collection->GetBuffer_by_Index( static_cast<int>(in_index) );
}


//// _____________________________________________________________________________
//// 指定したフォーマットから頂点メモリストリームを取得
//// _____________________________________________________________________________
//DX::Buffer::Interface_::SpRefCnt
//  MeshData::Object::GetVertexBuffer_by_TypeID(
//    DX::Layout::Buffer const& in_vtx_layout,
//    DX::VTX_TYPE_ID         in_vtx_format )
//{
//  return
//    m_sp_buf_collection->GetVertexBuffer_by_TypeID(
//      in_vtx_layout, in_vtx_format );
//}
//
//// _____________________________________________________________________________
//// 指定したフォーマットから頂点メモリストリームを取得 ※ const仕様
//// _____________________________________________________________________________
//DX::Buffer::Interface_::SpRefCnt::Const
//  MeshData::Object::GetVertexBuffer_by_TypeID(
//    DX::Layout::Buffer const& in_vtx_layout,
//    DX::VTX_TYPE_ID         in_vtx_format ) const
//{
//  return
//    m_sp_buf_collection->GetVertexBuffer_by_TypeID(
//      in_vtx_layout, in_vtx_format );
//}



//// _____________________________________________________________________________
////
//// _____________________________________________________________________________
//DX::D3DVertexBuffer_ptr
//  MeshData::Object::GetDxVB( DX::TYPE_SLOT_INDEX in_slot_No ) const
//{
//  return 
//}


// _____________________________________________________________________________
/// @brief マトリクスの更新
/// 
/// @param[in] in_ptr_matrix_for_parent
///   : 親のマトリクスのポインタを指定します。
/// @copydetails doxycomment::arg_in_flag_interpolate
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::UpdateMatrix
    ( pin<CMatrix> in_ptr_matrix_for_parent
    , _in<bool   > in_flag_interpolate
    )
{
  // マトリクス設定
  CVector3 vscl(1,1,1), vrot(0,0,0), vpos(0,0,0);
  // スケール
  if( auto sp_keylist = m_wp_relation_keylist_scl.lock() )
  {
    zzf_getKeyListVec( sp_keylist, in_flag_interpolate, vscl );
  }
  // 角度
  if( auto sp_keylist = m_wp_relation_keylist_rot.lock() )
  {
    zzf_getKeyListVec( sp_keylist, in_flag_interpolate, vrot );
  }
  // 座標
  if( auto sp_keylist = m_wp_relation_keylist_pos.lock() )
  {
    zzf_getKeyListVec( sp_keylist, in_flag_interpolate, vpos );
  }

  CMatrix& local_matrix = m_blend_matrix[ 0 ];
  local_matrix.Identity();
  local_matrix.Scaling( this->m_vec_scl * vscl );
  local_matrix.RotYrad( this->m_vec_rot.y + vrot.y );
  local_matrix.RotXrad( this->m_vec_rot.x + vrot.x );
  local_matrix.RotZrad( this->m_vec_rot.z + vrot.z );
  local_matrix.Translate( this->m_vec_pos + vpos );

  // 親マトリクスの乗算
  if( in_ptr_matrix_for_parent )
  {
    local_matrix *= *in_ptr_matrix_for_parent;
  }

  // ボーン
  sdptr<Bone> sp_bone = this->m_wp_bone_root.lock();
  CMatrix* ptr_matrix = &m_blend_matrix[ 1 ];
  while( sp_bone )
  {
    ptr_matrix =
      sp_bone->UpdateMatrix
        ( ptr_matrix
        , &local_matrix
        , in_flag_interpolate
        );
    sp_bone = sp_bone->GetLinkNext();
  }
}


// _____________________________________________________________________________
/// @brief ｚソート済みインデックスの設定
/// 
/// @param[in] in_eye_pos
///   : 視点座標を指定します。
/// @param[in] in_flag_order
///   : ソート方向を指定します。\n
///   : 0 - 昇順\n
///   : 1 - 降順\n
/// @param[in] in_vec_trans_tbl
///   : 
/// @param[out] out_poly_idx_table
///   : 変換済みインデックステーブルを格納するための配列を渡します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::GetZSortIndex
    ( _in <CVector3     > in_eye_pos
    , _in <bool         > in_flag_order
    , _in <Array_Vector3> in_vec_trans_tbl
    , rout<Array_Int    > out_poly_idx_table
    )
{
  //if( !m_sp_layout_buf ){ return; }

  //// 頂点要素を取得
  //DX::VertexStreamLayout::SpRefCnt
  //  sp_vsl_xyz =
  //    m_sp_layout_buf->GetVertexStreamLayout_by_Format( DX::VF_XYZ );
  //DX::VertexStreamLayout::SpRefCnt
  //  sp_vsl_bw =
  //    m_sp_layout_buf->GetVertexStreamLayout_by_Format( DX::VF_BLEND_WEIGHT1 );
  //DX::VertexStreamLayout::SpRefCnt
  //  sp_vsl_bi =
  //    m_sp_layout_buf->GetVertexStreamLayout_by_Format( DX::VF_BLEND_INDEX );

  //// 座標を保持している頂点バッファを取得
  //DX::Buffer::Interface_::SpRefCnt
  //  sp_vsb_xyz =
  //    m_sp_buf_collection->GetVertexBuffer_by_TypeID(
  //      *m_sp_layout_buf,
  //      DX::VF_XYZ );
  //DX::Buffer::Interface_::SpRefCnt
  //  sp_vsb_bw =
  //    m_sp_buf_collection->GetVertexBuffer_by_TypeID(
  //      *m_sp_layout_buf,
  //      DX::VF_BLEND_WEIGHT1 );
  //DX::Buffer::Interface_::SpRefCnt
  //  sp_vsb_bi =
  //    m_sp_buf_collection->GetVertexBuffer_by_TypeID(
  //      *m_sp_layout_buf,
  //      DX::VF_BLEND_INDEX );

  //if( !sp_vsb_xyz  ||  !sp_vsb_bw  ||  !sp_vsb_bi )
  //{
  //  return;
  //}

  // 頂点データロック
  //const int vtx_offs_xyz = sp_vsl_xyz->GetElementOffs( DX::VF_XYZ );
  //const int vtx_size_xyz = sp_vsl_xyz->GetVertexSize();
  //const int vtx_offs_bw  = sp_vsl_bw ->GetElementOffs( DX::VF_BLEND_WEIGHT1 );
  //const int vtx_size_bw  = sp_vsl_bw ->GetVertexSize();
  //const int vtx_offs_bi  = sp_vsl_bi ->GetElementOffs( DX::VF_BLEND_INDEX );
  //const int vtx_size_bi  = sp_vsl_bi ->GetVertexSize();
  //DX::AutoLockVB<char> vb_xyz( sp_vsb_xyz->GetVB(), vtx_offs_xyz );
  //DX::AutoLockVB<char> vb_bw ( sp_vsb_bw->GetVB(),  vtx_offs_bw );
  //DX::AutoLockVB<char> vb_bi ( sp_vsb_bi->GetVB(),  vtx_offs_bi );


  // インデックスデータを取得
  const int poly_num = static_cast<int>(m_vtx_num) / 3;
  Core::unique_ptr<float[]> length_table{ CPL_NEW(float)[ poly_num ] };
  Core::unique_ptr<int3[]>  index_table { CPL_NEW(int3 )[ poly_num ] };
  try { // バッファの自動ロックでの例外をキャッチするため。
    //DX::AutoLockIB<int3>    poly_table_source( m_sp_idx_buf->GetIB() ); // インデックスバッファロック
    DX::Buffer::AutoMapRW<int3> poly_table_source( m_sp_idx_buf ); // インデックスバッファの自動ロック
    CPL_MEMCPY
      ( &index_table[0]
      , poly_table_source
      , poly_num * sizeof(int3)
      );

    // ポリゴンインデックスリストを準備（初期０～Ｎまで連番とする）
    // ※ 頂点インデックスをソートするより、ポリゴンインデックスをソートした方が速いので。
    out_poly_idx_table.Resize( poly_num );
  }
  catch( ... )
  {
    // 例外が投げられた場合、インデックスバッファがロックできない可能性が大きい
    return;
  }

  //
  //char const* vtx_xyz_addr = vb_xyz;
  //char const* vtx_bw_addr  = vb_bw;
  //char const* vtx_bi_addr  = vb_bi;
  // 重心までの距離をテーブルに設定
  //CPL_LOOP2( poly_num, poly_idx )
  for( int poly_idx = 0; poly_idx < poly_num; ++poly_idx )
  {
    int index[3] = {
      index_table[ poly_idx ].x,
      index_table[ poly_idx ].y,
      index_table[ poly_idx ].z
    };

    // 長さ初期化
    length_table[ poly_idx ] = 0;
    // ポリゴンインデックス設定
    out_poly_idx_table[ poly_idx ] = poly_idx;

    for( int vtx_no = 0; vtx_no < 3; ++vtx_no )
    {
      //const int vtx_size = sp_vsl_xyz->GetVertexSize();
      //const int offset = vtx_size * index[ vtx_no ];
      ////DX::Vtx::XYZ const*       ptr_xyz =
      ////  reinterpret_cast<DX::Vtx::XYZ const*>(vtx_xyz_addr + offset);
      //DX::Vtx::BWeight1 const*  ptr_bw  =
      //  reinterpret_cast<DX::Vtx::BWeight1 const*>(vtx_bw_addr + offset);
      //DX::Vtx::BIndex const*    ptr_bi  =
      //  reinterpret_cast<DX::Vtx::BIndex const*>(vtx_bi_addr + offset);

      // 
      //CMatrix mtx =
      //  m_blend_matrix[ ptr_bi->bi0 ] * ptr_bw->bw0 +
      //  m_blend_matrix[ 0 ] * (1.0f - ptr_bw->bw0);

      float3 pos( in_vec_trans_tbl[ index[ vtx_no ] ] );

      //
      pos.x -= in_eye_pos.x;
      pos.y -= in_eye_pos.y;
      pos.z -= in_eye_pos.z;

      float length = Math::D3<float>::GetVecLengthSq( &pos.x );
      length_table[ poly_idx ] += length;
    }
  }

  // ソート
  int sp = 1, left, right;
  Core::unique_ptr<int[]> stack_L{ CPL_NEW(int)[ poly_num + 1 ] };
  Core::unique_ptr<int[]> stack_R{ CPL_NEW(int)[ poly_num + 1 ] };
  stack_L[ sp ] = 0; // スタック左側初期値
  stack_R[ sp ] = poly_num - 1; // スタック右側初期値
  float mid_len;

  do { // スタックループ
    left  = stack_L[ sp ];
    right = stack_R[ sp ];
    --sp;
    
    do { // 部分配列ループ
      mid_len = (length_table[ left ] + length_table[ right ]) * 0.5f; // 基準値選択
      int i = left, j = right;
      
      do { // 分割ループ
        if( in_flag_order == 0 ) // 昇順
        {
          while( length_table[ i ] < mid_len ){ ++i; } // 左側交換要素検索
          while( length_table[ j ] > mid_len ){ --j; } // 右側交換要素検索
        }
        else
        {
          while( length_table[ i ] > mid_len ){ ++i; } // 左側交換要素検索
          while( length_table[ j ] < mid_len ){ --j; } // 右側交換要素検索
        }
        
        if( i <= j )
        {
          Swap( length_table[ i ],       length_table[ j ] ); // 比較要素交換
          Swap( out_poly_idx_table[ i ], out_poly_idx_table[ j ] ); // インデックス交換
          ++i;
          --j;
        }
      } while( i <= j ); // 分割ループ条件
      
      if( i < right )
      {
        ++sp;
        stack_L[ sp ] = i;
        stack_R[ sp ] = right;
      }
      right = j;
    } while( left < right ); // 部分配列ループ条件
  } while( sp > 0 ); // スタックループ条件
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 現在の頂点データを元に、法線を計算する
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::Object::UpdateNormalVector()
{
  if( !m_sp_layout_buf ){ return; }

  // 頂点要素を取得
  //DX::VertexStreamLayout::SpRefCnt
  //  sp_vsl_xyz =
  //    m_sp_layout_buf->GetVertexStreamLayout_by_Format( DX::VF_XYZ );
  //DX::VertexStreamLayout::SpRefCnt
  //  sp_vsl_normal =
  //    m_sp_layout_buf->GetVertexStreamLayout_by_Format( DX::VF_NORMAL );
  //DX::VertexStreamLayout::SpRefCnt
  //  sp_vsl_bw =
  //    m_sp_layout_buf->GetVertexStreamLayout_by_Format( DX::VF_BLEND_WEIGHT1 );
  //DX::VertexStreamLayout::SpRefCnt
  //  sp_vsl_bi =
  //    m_sp_layout_buf->GetVertexStreamLayout_by_Format( DX::VF_BLEND_INDEX );

  // 座標を保持している頂点バッファを取得
  // vertex
  sdptr<DX::Buffer::Collection::BufIface>
    sp_buf_vertex =
      m_sp_buf_collection->GetBuffer_by_Index( (int)eBufferIndex::Vertex );
  if( !sp_buf_vertex ){ return; }

  // normal
  sdptr<DX::Buffer::Collection::BufIface>
    sp_buf_normal =
      m_sp_buf_collection->GetBuffer_by_Index( (int)eBufferIndex::Normal );
  if( !sp_buf_normal ){ return; }

  // blend wegith
  sdptr<DX::Buffer::Collection::BufIface>
    sp_buf_BW =
      m_sp_buf_collection->GetBuffer_by_Index( (int)eBufferIndex::BlendWeight );
  if( !sp_buf_BW ){ return; }

  // blend index
  sdptr<DX::Buffer::Collection::BufIface>
    sp_buf_BI =
      m_sp_buf_collection->GetBuffer_by_Index( (int)eBufferIndex::BlendIndex );
  if( !sp_buf_BI ){ return; }
  

  // バッファロック
  DX::Buffer::AutoMapRW< DX::Vtx::XYZ >      xyz( sp_buf_vertex );
  DX::Buffer::AutoMapRW< DX::Vtx::Normal >   normal( sp_buf_normal );
  DX::Buffer::AutoMapRW< DX::Vtx::BWeight1 > blend_weight( sp_buf_BW );
  DX::Buffer::AutoMapRW< DX::Vtx::BIndex >   blend_index( sp_buf_BI );
  DX::Buffer::AutoMapRW< U32 >               index( m_sp_idx_buf );

  //const int vtx_offs_xyz    = sp_vsl_xyz->GetElementOffs( DX::VF_XYZ );
  //const int vtx_size_xyz    = sp_vsl_xyz->GetVertexSize();
  //const int vtx_offs_normal = sp_vsl_normal->GetElementOffs( DX::VF_NORMAL );
  //const int vtx_size_normal = sp_vsl_normal->GetVertexSize();
  //const int vtx_offs_bw     = sp_vsl_bw->GetElementOffs( DX::VF_BLEND_WEIGHT1 );
  //const int vtx_size_bw     = sp_vsl_bw->GetVertexSize();
  //const int vtx_offs_bi     = sp_vsl_bi->GetElementOffs( DX::VF_BLEND_INDEX );
  //const int vtx_size_bi     = sp_vsl_bi->GetVertexSize();
  //DX::AutoLockVB<DX::Vtx::XYZ>    vb_xyz   ( sp_vsb_xyz->GetVB(),    vtx_offs_xyz,    0, vtx_size_xyz );
  //DX::AutoLockVB<DX::Vtx::Normal> vb_normal( sp_vsb_normal->GetVB(), vtx_offs_normal, 0, vtx_size_normal );
  //DX::AutoLockIB<U32>             ib( m_sp_idx_buf->GetIB() );
  ////
  //U32* ptr_index32 = ib;
  //U16* ptr_index16 = reinterpret_cast<U16*>(ptr_index32);
  //D3DINDEXBUFFER_DESC desc;
  //this->m_sp_idx_buf->GetIB()->GetDesc( &desc );
  //const int is_index16 = desc.Format == D3DFMT_INDEX16;
  const U32 index_num  = this->m_poly_num * 3;
  //CVector3 vtx[ 3 ];
  
  // 法線バッファ初期化
  CPL_LOOP2( m_vtx_num, i )
  {
    normal[ i ].nx = 0.0f;
    normal[ i ].ny = 0.0f;
    normal[ i ].nz = 0.0f;
  }
  //
  U32 idx0, idx1, idx2;
  for( U32 element_idx = 0; element_idx < index_num; element_idx += 3 )
  {
    // インデックス取得
    idx0 = index[ element_idx   ];
    idx1 = index[ element_idx+1 ];
    idx2 = index[ element_idx+2 ];
    // 法線を求める
    CVector3 poly_nor;
    Math::D3<float>::GetNormal3p(
      poly_nor, &xyz[idx0].x, &xyz[idx1].x, &xyz[idx2].x );
    // 法線を加算していく
    normal[ idx0 ] = DX::Vtx::Normal( poly_nor.x, poly_nor.y, poly_nor.z );// tmp_normal[ idx0 ].w + 1 );
    normal[ idx1 ] = DX::Vtx::Normal( poly_nor.x, poly_nor.y, poly_nor.z );// tmp_normal[ idx1 ].w + 1 );
    normal[ idx2 ] = DX::Vtx::Normal( poly_nor.x, poly_nor.y, poly_nor.z );// tmp_normal[ idx2 ].w + 1 );
  }

  // 法線を正規化
  CPL_LOOP2( m_vtx_num, vtx_idx )
  {
    Math::D3<float>::VecNormalize( &normal[ vtx_idx ].nx );
  }
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ｚソート済みポリゴンインデックスを元に、インデックスバッファを並び替え
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Object::UpdateSortIndex(
    Core::Array::Dynamic<int> const& in_poly_idx_tbl )
{
  // インデックスバッファロック
  DX::Buffer::AutoMapRW<U32> index( this->m_sp_idx_buf );
  // 一時バッファを作成
  const U32 element_num = static_cast<U32>(this->m_sp_idx_buf->GetElementNum());
  Core::Array::Constant<U32> tmp_buf_idx( element_num );

  const U32 poly_num = GetPolygonNum();
  // 一時コピー
  CPL_LOOP2( element_num, i )
  {
    tmp_buf_idx[ i ] = index[ i ];
  }

  // 並び替えコピー
  for( U32 poly_idx = 0; poly_idx < poly_num; ++poly_idx )
  {
    const int base_idx_dest = poly_idx * 3;
    const int base_idx_src  = in_poly_idx_tbl[ poly_idx ] * 3;
    index[ base_idx_dest + 0 ] = tmp_buf_idx[ base_idx_src + 0 ];
    index[ base_idx_dest + 1 ] = tmp_buf_idx[ base_idx_src + 1 ];
    index[ base_idx_dest + 2 ] = tmp_buf_idx[ base_idx_src + 2 ];
  }
}



//// _____________________________________________________________________________
//int DataType_to_StreamIndex( VTX_DATA_TYPE in_type )
//{
//  static const int to_stream[ VDT_NUM ] = {
//    -1,
//    MeshFileInfo::VSI_VECTOR,
//    MeshFileInfo::VSI_VECTOR,
//    MeshFileInfo::VSI_BLEND, MeshFileInfo::VSI_BLEND, MeshFileInfo::VSI_BLEND,
//    MeshFileInfo::VSI_NORMAL,
//    MeshFileInfo::VSI_PSIZE,
//    MeshFileInfo::VSI_TANGENT,
//    MeshFileInfo::VSI_BINORMAL,
//    MeshFileInfo::VSI_TESSFACTOR,
//    MeshFileInfo::VSI_FOG,
//    MeshFileInfo::VSI_DEPTH,
//    MeshFileInfo::VSI_TEXCOORD, MeshFileInfo::VSI_TEXCOORD,
//    MeshFileInfo::VSI_TEXCOORD, MeshFileInfo::VSI_TEXCOORD,
//    MeshFileInfo::VSI_TEXCOORD, MeshFileInfo::VSI_TEXCOORD,
//    MeshFileInfo::VSI_TEXCOORD, MeshFileInfo::VSI_TEXCOORD,
//    MeshFileInfo::VSI_COLOR, MeshFileInfo::VSI_COLOR,
//    MeshFileInfo::VSI_COLOR, MeshFileInfo::VSI_COLOR,
//    MeshFileInfo::VSI_COLOR, MeshFileInfo::VSI_COLOR,
//    MeshFileInfo::VSI_COLOR, MeshFileInfo::VSI_COLOR,
//  };
//  return to_stream[ in_type ];
//}
//
//// _____________________________________________________________________________
//void MeshData::Object::zzf_AddVertex_Stream_(
//      const int       in_insert_idx,
//      CVT_base const* in_ptr_data )
//{
//  const int vtx_type = in_ptr_data->type_ID;
//  const int vtx_size = in_ptr_data->size;
////  const int stream   = DataType_to_StreamIndex( vtx_type );
//
//  CVT_DataPack dp;
//  if(
//
//  m_sp_buf_collection->AddVertex(
//    in_insert_idx,
//    CVT_DataPack( &CVT_XYZ(
//
//  if( stream >= 0 )
//  {
//    SmartPtr< DX::BaseVertexBuffer >::Auto& sp_vtx_buf = io_vb_table[ stream ];
//
//    if( !sp_vtx_buf )
//    {
//      switch( stream )
//      {
//      case MeshFileInfo::VSI_VECTOR:      sp_vtx_buf = new VEB_Vector();     break;
//      case MeshFileInfo::VSI_BLEND:       sp_vtx_buf = new VEB_Blend();      break;
//      case MeshFileInfo::VSI_NORMAL:      sp_vtx_buf = new VEB_Normal();     break;
//      case MeshFileInfo::VSI_COLOR:       sp_vtx_buf = new VEB_Color();      break;
//      case MeshFileInfo::VSI_PSIZE:       sp_vtx_buf = new VEB_PSize();      break;
//      case MeshFileInfo::VSI_DEPTH:       sp_vtx_buf = new VEB_Depth();      break;
//      case MeshFileInfo::VSI_TANGENT:     sp_vtx_buf = new VEB_Tangent();    break;
//      case MeshFileInfo::VSI_BINORMAL:    sp_vtx_buf = new VEB_BINormal();   break;
//      case MeshFileInfo::VSI_TESSFACTOR:  sp_vtx_buf = new VEB_TessFactor(); break;
//      }
//      sp_vtx_buf->Resize( in_vtx_num );
//    }
//
//    if( in_insert_idx < 0 )
//    {
//      // 最後尾にデータをコピー
//      sp_vtx_buf->SetData( in_vtx_num - 1, in_ptr_data->GetDataAddr() );
//    }
//    else
//    {
//      // データシフト
//      sp_vtx_buf->ShiftData( in_insert_idx, m_vtx_num, 1 );
//      // データコピー
//      sp_vtx_buf->SetData( in_insert_idx, in_ptr_data->GetDataAddr() );
//    }
//  }
//}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 頂点の追加
// ※ 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::AddVertex
    ( _in<DX::TYPE_INDEX  > in_insert_idx
    , _in<CVtxSetDataTypes> in_vtx_data_types
    )
{
  HRESULT f_ret = S_FALSE;
  try {
    for( CVtxSetDataTypes const* ptr_set_data_node = &in_vtx_data_types;
         ptr_set_data_node;
         ptr_set_data_node = ptr_set_data_node->GetNodeNext() )
    {
      // バッファインデックスを取得
      eBufferIndex
        buf_type_idx =
          zzf_GetBufferIndex_by_VertexTypeID( ptr_set_data_node->type_format );
      if( buf_type_idx == eBufferIndex::Error ) continue;
      // バッファポインタを取得
      sdptr<DX::Buffer::Collection::BufIface>
        sp_vtx_buf =
          m_sp_buf_collection->GetBuffer_by_Index( static_cast<size_t>(buf_type_idx) );
      // 基底クラスのスマポなのでキャストして DX::Buffer::DynamicEX_Vertex* に変換
      DX::Buffer::DynamicEX_Vertex*
        ptr_vtx_buf =
          SmartCast<DX::Buffer::DynamicEX_Vertex*>( sp_vtx_buf );
      // データ書き込み
      ptr_vtx_buf->Add( in_insert_idx, ptr_set_data_node->m_ptr_data );
      //
      f_ret = S_OK;
    }
  }
  catch(...)
  {
    return S_FALSE; // マップに失敗した可能性が高い？
  }

  return f_ret;
}


//// _____________________________________________________________________________
//// 頂点データ取得用汎用関数
//// _____________________________________________________________________________
//bool zzf_meshObject_GetVertexData_(
//      int                           in_vtx_index,
//      CVT_base*                     out_ptr_data,
//      DX::BaseVertexBuffer::SpAuto* io_vb_table )
//{
//  const int vtx_type = out_ptr_data->type_ID;
//  const int vtx_size = out_ptr_data->size;
//  const int stream   = DataType_to_StreamIndex( vtx_type );
//  if( stream >= 0 )
//  {
//    SmartPtr< DX::BaseVertexBuffer >::Auto& sp_vtx_buf = io_vb_table[ stream ];
//
//    if( sp_vtx_buf )
//    {
//      sp_vtx_buf->GetData( in_vtx_index, out_ptr_data->GetDataAddr(), vtx_size );
//
//      return true;
//    }
//  }
//
//  return false;
//}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 頂点データを取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::GetVertexData
    ( DX::TYPE_INDEX    in_vtx_index
    , CVtxGetDataTypes& out_vtx_data_types
    ) const
{
  HRESULT f_ret = S_FALSE;
  
  try {
    for( CVtxGetDataTypes* ptr_get_data_node = &out_vtx_data_types;
         ptr_get_data_node;
         ptr_get_data_node = ptr_get_data_node->GetNodeNext() )
    {
      // バッファインデックスを取得
      eBufferIndex
        buf_type_idx =
          zzf_GetBufferIndex_by_VertexTypeID( ptr_get_data_node->type_format );
      if( buf_type_idx == eBufferIndex::Error ) continue;

      // バッファポインタを取得
      sdptr<DX::Buffer::Collection::BufIface>
        sp_vtx_buf =
          m_sp_buf_collection->GetBuffer_by_Index( static_cast<size_t>(buf_type_idx) );
      if( !sp_vtx_buf ) continue;
      // バッファへ書き込み
      sp_vtx_buf->GetData( in_vtx_index, ptr_get_data_node->m_ptr_data );
      //
      f_ret = S_OK;
    }
  }
  catch(...)
  {
    return S_FALSE; // マップに失敗した可能性が高い？
  }

  return f_ret;
}


//// _____________________________________________________________________________
//// 頂点データ設定用汎用関数
//// _____________________________________________________________________________
//bool zzf_meshObject_SetVertexData_(
//      int                           in_vtx_index,
//      CVT_base const*               in_ptr_data,
//      DX::BaseVertexBuffer::SpAuto* io_vb_table,
//      CVT_base*                     out_ptr_old_data )
//{
//  const int vtx_type = in_ptr_data->type_ID;
//  const int vtx_size = in_ptr_data->size;
//  const int stream   = DataType_to_StreamIndex( vtx_type );
//  if( stream >= 0 )
//  {
//    SmartPtr< DX::BaseVertexBuffer >::Auto& sp_vtx_buf = io_vb_table[ stream ];
//
//    if( sp_vtx_buf )
//    {
//      U8 tmp_buf[ 256 ] = { 0 }
//      if( out_ptr_old_data )
//      {
//        sp_vtx_buf->GetData( in_vtx_index, tmp_buf, vtx_size );
//      }
//
//      sp_vtx_buf->SetData( in_vtx_index, &in_ptr_data->GetDataAddr(), vtx_size );
//
//      if( out_ptr_old_data )
//      {
//        ::memcpy( out_ptr_old_data->GetDataAddr(), tmp_buf, vtx_size );
//      }
//
//      return true;
//    }
//  }
//
//  return false;
//}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 頂点データの設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::SetVertexData
    ( DX::TYPE_INDEX          in_vtx_index
    , CVtxSetDataTypes const& in_vtx_data_types
    )
{
  HRESULT f_ret = S_FALSE;
  
  try {
    for( CVtxSetDataTypes const* ptr_set_data_node = &in_vtx_data_types;
         ptr_set_data_node;
         ptr_set_data_node = ptr_set_data_node->GetNodeNext() )
    {
      // バッファインデックスを取得
      eBufferIndex
        buf_type_idx =
          zzf_GetBufferIndex_by_VertexTypeID( ptr_set_data_node->type_format );
      if( buf_type_idx == eBufferIndex::Error ) continue;

      // バッファポインタを取得
      sdptr<DX::Buffer::Collection::BufIface>
        sp_vtx_buf =
          m_sp_buf_collection->GetBuffer_by_Index( static_cast<size_t>(buf_type_idx) );
      if( !sp_vtx_buf ) continue;
      // バッファへ書き込み
      sp_vtx_buf->SetData( in_vtx_index, ptr_set_data_node->m_ptr_data );
      //
      f_ret = S_OK;
    }
  }
  catch(...)
  {
    return S_FALSE; // マップに失敗した可能性が高い？
  }

  return f_ret;
}




// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// インデックス追加
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//HRESULT
//  MeshData::Object::AddIndex(
//    DX::TYPE_INDEX in_insert_idx,
//    DX::TYPE_INDEX in_vtx_idx )
//{
//  if( m_sp_idx_buf )
//  {
//    // 拡張コントローラへ渡すため、読み書き可能バッファへ変換
//    DX::Buffer::CPU_RW*
//      ptr_buf =
//        SmartCast<DX::Buffer::CPU_RW*>(m_sp_idx_buf);
//    if( !ptr_buf ) return S_FALSE;
//    // 拡張コントローラ作成
//    DX::Buffer::Controller buf_ctrl( ptr_buf );
//    U32 add_index = in_vtx_idx;
//    if( !buf_ctrl.Add( in_insert_idx, &add_index ) )
//    {
//      return S_FALSE;
//    }
//  }
//  else
//  {
//    return S_FALSE;
//  }
//
//  return S_OK;
//}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 単体インデックス取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::GetIndex
    ( DX::TYPE_INDEX  in_poly_idx
    , int             in_vtx_no
    , DX::TYPE_INDEX& out_index
    ) const
{
  if( m_sp_idx_buf )
  {
    return m_sp_idx_buf->GetData( in_poly_idx*3+in_vtx_no, &out_index );
  }

  return S_FALSE;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 単体インデックス設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::SetIndex
    ( DX::TYPE_INDEX  in_poly_idx
    , int             in_vtx_no
    , DX::TYPE_INDEX  in_index
    , DX::TYPE_INDEX* out_ptr_index
    )
{
  if( m_sp_idx_buf )
  {
    if( out_ptr_index )
    {
      m_sp_idx_buf->GetData( in_poly_idx * 3 + in_vtx_no, out_ptr_index );
    }
    m_sp_idx_buf->SetData( in_poly_idx * 3 + in_vtx_no, &in_index );

    return S_OK;
  }

  return S_FALSE;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ポリゴンインデックス追加
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::AddPolygon
    ( _in<DX::TYPE_INDEX > in_insert_poly_idx
    , _in<DX::TYPE_INDEX3> in_index_list
    )
{
  if( m_sp_idx_buf )
  {
    //U32 idx[] = { in_index_list.x, in_index_list.y, in_index_list.z };

    // 追加と判定
    if( !m_sp_idx_buf->Add( in_insert_poly_idx, &in_index_list.x, sizeof(in_index_list) ) )
    {
      return S_FALSE;
    }
  }
  else
  {
    return S_FALSE;
  }

  return S_OK;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ポリゴンの削除
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT MeshData::Object::DeletePolygon( DX::TYPE_INDEX in_poly_index )
{
  if( m_sp_idx_buf )
  {
    // 削除と判定
    if( !m_sp_idx_buf->Delete( in_poly_index ) )
    {
      return S_FALSE;
    }
  }
  else
  {
    return S_FALSE;
  }

  return S_OK;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ポリゴンの削除　※ リスト指定仕様
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::DeletePolygonList( size_t* in_poly_table, UINT in_num )
{
  if( m_sp_idx_buf )
  {
    // 追加と判定
    if( !m_sp_idx_buf->DeleteTable( in_poly_table, in_num ) )
    {
      return S_FALSE;
    }
  }
  else
  {
    return S_FALSE;
  }

  return S_OK;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ポリゴンインデックス取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::GetPolyIndex
    ( DX::TYPE_INDEX   in_poly_idx
    , DX::TYPE_INDEX3& out_index
    ) const
{
  if( m_sp_idx_buf )
  {
    U32 idx[3];
    m_sp_idx_buf->GetData( in_poly_idx * 3, idx, 3 );
    out_index.x = idx[0];
    out_index.y = idx[1];
    out_index.z = idx[2];

    return S_OK;
  }

  return S_FALSE;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ポリゴンインデックスの設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::SetPolyIndex
    ( _in<DX::TYPE_INDEX > in_poly_idx
    , _in<DX::TYPE_INDEX3> in_index
    )
{
  if( m_sp_idx_buf )
  {
    m_sp_idx_buf->SetData( in_poly_idx * 3, &in_index.x, 3 );

    return S_OK;
  }

  return S_FALSE;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 保持する頂点から、指定した座標に最も近い頂点インデックスを取得。
// 該当しない場合、INVALID_INDEX32を返す。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
U32 MeshData::Object::GetNearIndex( CVector3 const& in_pos ) const
{
  U32 vtx_num = GetVertexNum();
  if( vtx_num == 0 )
  {
    return INVALID_INDEX32;
  }
  U32 idx = 0;
  float len, len_min = 1024 * 1024 * 1024;

  try
  {
    // 座標頂点バッファを取得
    sdptr<DX::Buffer::Collection::BufIface>
      sp_buf_vtx =
        m_sp_buf_collection->GetBuffer_by_Index( static_cast<size_t>(eBufferIndex::Vertex) );
    // バッファのオートロック
    DX::Buffer::AutoMapR<DX::Vtx::XYZ> xyz_table( sp_buf_vtx );

    CPL_LOOP2( vtx_num, vtx_idx )
    {
      DX::Vtx::XYZ const& xyz = xyz_table[ vtx_idx ];
      CVector3 vec(
        xyz.x - in_pos.x,
        xyz.y - in_pos.y,
        xyz.z - in_pos.z );

      len = Math::D3<float>::GetVecLengthSq( vec ); // 距離（の２乗）を求める。
      if( len < len_min )
      {
        idx = vtx_idx;
        len_min = len;
      }
    }
  }
  catch(...)
  {
    return INVALID_INDEX32;
  }

  return idx;
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// オブジェクト描画
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::Object::Draw( DrawObjectDesc const& in_draw_obj_desc ) const
{
  if( m_wp_relation_shader.expired()  ||
      !m_sp_idx_buf )
  {
    return;
  }

  //
  DX::DXDeviceContext*
    ptr_d3d_devct = in_draw_obj_desc.m_ptr_d3d_emd_ctx;
  //
  CMatrix mtx_rot;
  mtx_rot.Identity();
  mtx_rot.RotZrad( this->m_vec_rot.z );
  mtx_rot.RotXrad( this->m_vec_rot.x );
  mtx_rot.RotYrad( this->m_vec_rot.y );

  // ビルボード用マトリクスの作成
  CMatrix mtx_BBR;
  mtx_BBR.Identity();
  if( m_flag_billboard )
  {
    CMatrix const& mtx = m_blend_matrix[ 0 ];
    float3  pos( mtx._41, mtx._42, mtx._43 );
    mtx_BBR.Translate( -pos.x, -pos.y, -pos.z );
    mtx_BBR *= mtx_rot;
    mtx_BBR.Translate( pos.x, pos.y, pos.z );
  }

  // 
  m_sp_render_collection->RenderSetup( ptr_d3d_devct );

//  // シェーダパラメータ設定
//  zzf_updateShaderData_( in_draw_obj_desc, &mtx_BBR );
//
////  Shader const* ptr_shader = static_cast<Shader const*>(m_wp_relation_shader);
//  MFI_ShaderInfoVS const&  vs_info         = m_wp_relation_shader->GetVS_Param();
//  MFI_ShaderInfoPS const&  ps_info         = m_wp_relation_shader->GetPS_Param();
//  SpCInputLayout           sp_input_layout = m_wp_relation_shader->GetInputLayout();
//  DX::DXVertexShader::ptr ptr_vtx_shader  = m_wp_relation_shader->GetDxVertexShader();
//  DX::DXPixelShader::ptr  ptr_pxl_shader  = m_wp_relation_shader->GetDxPixelShader();
//
//  // シェーダ設定
//  ptr_d3d_devct->IASetInputLayout( sp_input_layout->GetDxObject() );
//  ptr_d3d_devct->VSSetShader( ptr_vtx_shader, nullptr, 0 );
//  ptr_d3d_devct->PSSetShader( ptr_pxl_shader, nullptr, 0 );
//
//  // 頂点バッファ設定
//  ptr_d3d_devct->VSSetConstantBuffers( 0, 1, buf );
//  m_sp_buf_collection->SetStream();
//
//  // インデックスバッファの設定
//  ptr_d3d_devct->SetIndices( const_cast<IDirect3DIndexBuffer9*>(m_sp_idx_buf->GetIB()) );
//
//  // テクスチャを使用しているか？（レベル値として設定）
//  const int use_texture_level =
//    this->m_sp_layout_buf->IsTextureUsed();
//  CPL::Clamp( use_texture_level, 0, 4 ); // 値調整
//  // テクスチャ数
//  const int texture_table_num =
//    in_draw_obj_desc.m_ptr_tex_table ?
//      in_draw_obj_desc.m_ptr_tex_table->GetNum() : 0;
//  // テクスチャ設定
//  for( int texture_level_idx = 0;
//       texture_level_idx < use_texture_level;
//       ++texture_level_idx )
//  {
//    if( this->m_tex_index[texture_level_idx] < (U8)texture_table_num )
//    {
//      ptr_d3d_devct->SetTexture(
//        texture_level_idx,
//        (*in_draw_obj_desc.m_ptr_tex_table)[texture_level_idx] );
//    }
//  }
//  
//  // カリング設定
//  ptr_d3d_devct->SetRenderState( D3DRS_CULLMODE, m_flag_culling );

  // 描画
  ptr_d3d_devct->DrawIndexed( m_poly_num, 0, 0 );

  
  // ミラー対象として自身が設定されていたら、自身を参照元のマトリクスを用いて描画
  if( m_wp_mirror_object.lock()  &&  m_sp_mirror_context )
  {
    // ミラー用の設定（カリングとシェーダの設定？）
    m_sp_mirror_context->RenderSetup( ptr_d3d_devct );

    // 描画
    ptr_d3d_devct->DrawIndexed( m_poly_num, 0, 0 );
  }
}





// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 頂点データの要素削除
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT
  MeshData::Object::DeleteVertex
    ( DX::TYPE_INDEX in_del_index
    , int            in_del_num
    )
{
  sdptr<DX::Buffer::Collection::BufIface>
    sp_buf_vtx =
      m_sp_buf_collection->GetBuffer_by_Index( static_cast<size_t>(eBufferIndex::Vertex) );
  DX::Buffer::DynamicEX* ptr_buf_rw =
    SmartCast<DX::Buffer::DynamicEX*>( sp_buf_vtx );
  if( !ptr_buf_rw )
    return S_FALSE;

  try
  {
    // コントローラ
    ptr_buf_rw->Delete( in_del_index, in_del_num );
  }
  catch( HRESULT hr )
  {
    return hr;
  }
  catch(...)
  {
    return S_FALSE;
  }

  return S_OK;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 頂点データの要素数変更
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT MeshData::Object::ResizeVertexBuffer( int in_num )
{
  sdptr<DX::Buffer::Collection::BufIface>
    sp_buf_vtx =
      m_sp_buf_collection->GetBuffer_by_Index( static_cast<size_t>(eBufferIndex::Vertex) );
  DX::Buffer::DynamicEX* ptr_buf_rw =
    SmartCast<DX::Buffer::DynamicEX*>( sp_buf_vtx );
  if( !ptr_buf_rw )
    return S_FALSE;

  try
  {
    ptr_buf_rw->Resize( in_num );
  }
  catch( HRESULT hr )
  {
    return hr;
  }
  catch(...)
  {
    return S_FALSE;
  }

  return S_OK;
}




} // namespace CDI
} // namespace CPL
