/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2009/X/X - 2015/11/11
/// 
/// @brief  メッシュデータ構造、シェーダー周り。
/// 
/// ****************************************************************************


#include "CPL_CDI_MeshData.h"


namespace CPL {
namespace CDI {


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


// _____________________________________________________________________________
/// @brief Shader コピーコンストラクタ
/// 
/// @param[in] in_data : コピー元のShaderオブジェクトを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::Shader::Shader( cref<Shader> in_data )
  : td_base( in_data )
{
  m_sp_input_layout = in_data.GetCInputLayout();
  m_sp_vtx_shader   = in_data.GetCVertexShader();
  m_sp_pxl_shader   = in_data.GetCPixelShader();
  m_vs_param        = in_data.GetVS_Param();
  m_ps_param        = in_data.GetPS_Param();
}


// _____________________________________________________________________________
/// @brief Shader ムーブコンストラクタ
/// 
/// @param[in] in_data : ムーブ元のShaderオブジェクトを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::Shader::Shader( rvref<Shader> in_data )
  : td_base( std::move(in_data) )
{
  m_sp_input_layout = std::move( in_data.m_sp_input_layout );
  m_sp_vtx_shader   = std::move( in_data.m_sp_vtx_shader );
  m_sp_pxl_shader   = std::move( in_data.m_sp_pxl_shader );
  m_vs_param        = in_data.GetVS_Param();
  m_ps_param        = in_data.GetPS_Param();
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// シェーダー　データ構築
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Shader::zzf_setupData_by_File_
    ( _in<DX::DXDevice*      > in_ptr_d3d_dev
    , pin<MeshFileInfo::Chunk> in_ptr_chunk
    , rio<Array_DataSPtr     > io_table_for_data_pointer
    , rio<Array_ChunkPtr     > io_table_for_chunk_pointer )
{
  char_cptr ptr_data_addr = reinterpret_cast<char_cptr>(in_ptr_chunk);
  MFI_Shader const* ptr_info_shader =
    reinterpret_cast<MFI_Shader const*>(ptr_data_addr);

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


  m_vs_param = ptr_info_shader->m_vs_info;
  m_ps_param = ptr_info_shader->m_ps_info;

  /*
  // フォーマット検査
  int fmt_num      = static_cast<int>(ptr_info_shader->m_format_num);
  int fmt_buf_size = (fmt_num + 3) / 4 * 4; // 4byteアライメントしているので。
  // 頂点シェーダ宣言の作成
  D3DVERTEXELEMENT9 decl_table[ 64 ]; // このサイズはテキトー
  D3DVERTEXELEMENT9* ptr_decl = decl_table;
  int offs[4] = {0};
//  int f_normal    = false; // 法線フラグ（ライト計算を行うかの判定に使う）
//  int f_light     = false; // ライティングフラグ
  int f_light     = in_light_table.GetNum() > 0;
  int f_vtx_color = false; // 頂点カラーフラグ（頂点カラー or マテリアルカラーの判定に使う）
  int f_tex_uv    = false; // テクスチャフラグ
  int offs_normal = -1;
  // ストリーム０頂点シェーダ宣言の設定
  for( int i = 0; i < fmt_num; ++i )
  {
    int format = ptr_info_shader->m_format[ i ];
    switch( format )
    {
    case MeshFileInfo::VF_XYZ:          ptr_decl = DX::VtxElmXYZ     ().Setup( offs[0], ptr_decl, 0 ); break;
    case MeshFileInfo::VF_XYZW:         ptr_decl = DX::VtxElmXYZW    ().Setup( offs[0], ptr_decl, 0 ); break;
    case MeshFileInfo::VF_BLEND_WEIGHT: ptr_decl = DX::VtxElmBWeight0().Setup( offs[0], ptr_decl, 0 ); break;
    case MeshFileInfo::VF_BLEND_INDEX:  ptr_decl = DX::VtxElmBIndex  ().Setup( offs[0], ptr_decl, 0 ); break;
    case MeshFileInfo::VF_NORMAL:       offs_normal = offs[0];
                                        ptr_decl = DX::VtxElmNormal  ().Setup( offs[0], ptr_decl, 0 ); break;
    case MeshFileInfo::VF_PSIZE:        ptr_decl = DX::VtxElmPSize   ().Setup( offs[0], ptr_decl, 0 ); break;
    };
  }
  if( f_light  &&  offs_normal < 0 ) // ライトのための法線領域を追加するかどうか
  {
    ptr_decl = DX::VtxElmNormal().Setup( offs[0], ptr_decl, 0 );
  }
  // ストリーム１頂点シェーダ宣言の設定
  for( int i = 0; i < fmt_num; ++i )
  {
    int format = ptr_info_shader->m_format[ i ];

    switch( format )
    {
    case MeshFileInfo::VF_COLOR1:
    case MeshFileInfo::VF_COLOR2:
    case MeshFileInfo::VF_COLOR3:
    case MeshFileInfo::VF_COLOR4:
    case MeshFileInfo::VF_COLOR5:
    case MeshFileInfo::VF_COLOR6:
    case MeshFileInfo::VF_COLOR7:
    case MeshFileInfo::VF_COLOR8:
      ptr_decl = DX::VtxElmColor( format - MeshFileInfo::VF_COLOR1 ).Setup( offs[1], ptr_decl, 1 );
      f_vtx_color = true;
      break;
    };
  }
  // ストリーム２頂点シェーダ宣言の設定
  for( int i = 0; i < fmt_num; ++i )
  {
    int format = ptr_info_shader->m_format[ i ];
    
    switch( format )
    {
    case MeshFileInfo::VF_TEXCOORD1:
    case MeshFileInfo::VF_TEXCOORD2:
    case MeshFileInfo::VF_TEXCOORD3:
    case MeshFileInfo::VF_TEXCOORD4:
    case MeshFileInfo::VF_TEXCOORD5:
    case MeshFileInfo::VF_TEXCOORD6:
    case MeshFileInfo::VF_TEXCOORD7:
    case MeshFileInfo::VF_TEXCOORD8:
      ptr_decl = DX::VtxElmTex( format - MeshFileInfo::VF_TEXCOORD1 )( offs[2], ptr_decl, 2 );
      f_tex_uv = format - MeshFileInfo::VF_TEXCOORD1 + 1;
      break;
    };
  }
  // ストリーム３頂点シェーダ宣言の設定
  for( int i = 0; i < fmt_num; ++i )
  {
    int format = ptr_info_shader->m_format[ i ];

    switch( format )
    {
    case MeshFileInfo::VF_TANGENT:      ptr_decl = DX::VtxElmTangent   (3)( ptr_decl, offs[3] ); break;
    case MeshFileInfo::VF_BINORMAL:     ptr_decl = DX::VtxElmBINormal  (3)( ptr_decl, offs[3] ); break;
    case MeshFileInfo::VF_TESSFACTOR:   ptr_decl = DX::VtxElmTessFactor(3)( ptr_decl, offs[3] ); break;
    case MeshFileInfo::VF_FOG:          ptr_decl = DX::VtxElmFog       (3)( ptr_decl, offs[3] ); break;
    case MeshFileInfo::VF_DEPTH:        ptr_decl = DX::VtxElmDepth     (3)( ptr_decl, offs[3] ); break;
    };
  }
  D3DVERTEXELEMENT9 end = D3DDECL_END();
  *ptr_decl = end;
  */
  // 頂点シェーダ宣言の作成
//  m_ptr_declaration = new CDeclaration( in_ptr_d3d_dev, decl_table );
//
//  StringA buf;
//  // 頂点シェーダの作成
//  try {
//    // シェーダフラグメント用テーブルの作成
//    DX::ShaderCodeFragmentTable scft;
//    scft.Add( new DX::Shader::VSF::Input_Declaration( decl_table ) );
//    scft.Add( new DX::Shader::VSF::MatrixBlending( ptr_vsi.blend_mtx_max, ptr_vsi.blend_idx_num ) ); // ブレンディングを有効
//    scft.Add( new DX::Shader::VSF::NormalTransform() ); // 法線変換
//    scft.Add( new DX::Shader::VSF::VertexTransform() ); // 頂点変換
//    if( f_light )
//    {
//      scft.Add( new DX::Shader::VSF::SetupPixelShaderLighting() );
//    }
//    for( int i = 0; i < f_tex_uv; ++i )
//    {
//      scft.Add( new DX::Shader::VSF::Input_TexCoord(i) );
//      scft.Add( new DX::Shader::VSF::Output_TexCoord(i) );
//    }
//    DX::VSCode vs_code( scft );
//
//    buf = vs_code.GetCode();
//    m_ptr_vtx_shader = new CVertexShader( vs_code, "vs_2_0", 0 );
//#ifdef CPL_DEBUG
//    Core::FileStream filevs( SwS("vertex_shader.txt"), Core::FileStream::kWRITE_BINARY );
//    filevs << buf;
//#endif
//  }
//  catch(...)
//  {
//#ifdef CPL_DEBUG
//    Core::FileStream filevs( SwS("vertex_shader.txt"), Core::FileStream::kWRITE_BINARY );
//    filevs << buf;
//#endif
//  }
//
//  // ピクセルシェーダの作成
//  try {
//    DX::ShaderCodeFragmentTable scft;
////    scft.Add( new SetColor( 255,255,255,255 ) );
//    if( f_vtx_color )
//    {
//      scft.Add( new DX::Shader::PSF::Input_Color() );
//    }
//    else
//    {
//      scft.Add( new DX::Shader::PSF::MaterialColor() );
//    }
//    scft.Add( new DX::Shader::PSF::AmbientLight() );
//    if( f_light )
//    {
//      scft.Add( new DX::Shader::PSF::DirectionalLight(0) );
//    }
//    if( f_tex_uv )
//    {
//      scft.Add( new DX::Shader::PSF::Texture(1) );
//    }
//    DX::Shader::PSCode ps_code( scft );
//    buf = ps_code.GetCode();
//    m_ptr_pxl_shader = new CPixelShader( ps_code, "ps_2_0", 0 );
//#ifdef CPL_DEBUG
//    Core::FileStream fileps( SwS("pixel_shader.txt"), Core::FileStream::kWRITE_BINARY );
//    fileps << buf;
//#endif
//  }
//  catch(...)
//  {
//#ifdef CPL_DEBUG
//    Core::FileStream fileps( SwS("pixel_shader.txt"), Core::FileStream::kWRITE_BINARY );
//    fileps << buf;
//#endif
//  }
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// シェーダー　データの構築と関連付け
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Shader::zzf_setupRelation_
    ( rio<Array_DataSPtr       > io_table_for_data_pointer
    , rio<Array_ChunkPtr       > io_table_for_chunk_pointer
    , _in<Array_SpLightMaterial> in_light_table
    )
{
  //
  const MeshFileInfo::Chunk** pp_chunk = io_table_for_chunk_pointer.Find( this );
  if( !pp_chunk  ||  !(*pp_chunk) )
  {
    return;
  }

  // LayoutBufferの検索。
  MFI_Shader const* ptr_info_shader =
    static_cast<MFI_Shader const*>(*pp_chunk);
  void_sptr* psp_data =
    io_table_for_data_pointer.Find( ptr_info_shader->m_GID_declaration );
  if( !psp_data  ||  !(*psp_data) )
  {
    return;
  }

  // 頂点シェーダ宣言の設定。
  auto sp_layout_buf =
   std::static_pointer_cast<LayoutBuffer>(*psp_data);

  const U32 light_num = static_cast<U32>(in_light_table.size());
  int f_light = light_num > 0;
  // 使用テクスチャ数を求める。
  UINT tex_num = 0;
  UINT color_num = 0;
  //
  DX::Layout::Buffer::ElementTable
    element_table =
      sp_layout_buf->GetLayoutBuffer()->GetElementTable();
  UINT element_num = (UINT)element_table.GetNum();
  for( UINT i = 0; i < element_num; ++i )
  {
    char_cptr semantic_name = element_table[ i ].SemanticName;
    if( Core::StringA::str_ncmp_( semantic_name, "TEXCOORD", sizeof("TEXCOORD") ) == 0 )
    {
      ++tex_num;
    }
    if( Core::StringA::str_ncmp_( semantic_name, "COLOR", sizeof("COLOR") ) == 0 )
    {
      ++color_num;
    }
  }

  Core::StringA buf;
  // 頂点シェーダの作成
  try {
    // シェーダフラグメント用テーブルの作成
    DX::Shader::CodeFragmentCollection
      vs_code_frgm = 
        DX::Shader::VSF::VertexLayout( *sp_layout_buf->GetLayoutBuffer() ) +
        DX::Shader::VSF::MatrixBlending(
          m_vs_param.blend_mtx_max,
          m_vs_param.blend_idx_num,
          m_vs_param.blend_mtx_max ) + // ブレンディングを有効
        DX::Shader::VSF::NormalTransform() + // 法線変換
        DX::Shader::VSF::VertexTransform(); // 頂点変換
    if( f_light )
    {
      vs_code_frgm << DX::Shader::VSF::SetupPixelShaderLighting( 0,0,light_num );
    }
    for( UINT i = 0; i < tex_num; ++i )
    {
      vs_code_frgm
        << DX::Shader::VSF::Input_TexCoord(i)
        << DX::Shader::VSF::Output_TexCoord(i);
    }
    DX::Shader::VSCode vs_code( "VS_Main", vs_code_frgm );

    buf = vs_code.GetCode();
    m_sp_vtx_shader = CPL_MAKE_SHARED( CVertexShader, vs_code, "VS_Main" );
#ifdef CPL_DEBUG
    Core::FileStream
      filevs( SwS("dbg_vertex_shader.txt"),
              Core::FileStream::kWRITE_BINARY );
    filevs << buf;
#endif
  }
  catch(...)
  {
#ifdef CPL_DEBUG
    Core::FileStream
      filevs( SwS("dbg_vertex_shader.txt"),
              Core::FileStream::kWRITE_BINARY );
    filevs << buf;
#endif
  }

  // ピクセルシェーダの作成
  try {
    DX::Shader::CodeFragmentCollection ps_code_frgm;
//    scft.Add( new SetColor( 255,255,255,255 ) );
    if( color_num > 0 )
    {
      for( UINT i = 0; i < color_num; ++i )
      {
        ps_code_frgm << DX::Shader::PSF::Input_Color( color_num );
      }
    }
    else
    {
      ps_code_frgm << DX::Shader::CSF::Global_Material();
    }
    ps_code_frgm << DX::Shader::PSF::AmbientLight();
    if( f_light )
    {
      ps_code_frgm <<
        DX::Shader::PSF::DirectionalLight( static_cast<U32>(in_light_table.size()) );
    }
    if( tex_num > 0 )
    {
      ps_code_frgm << DX::Shader::PSF::Texture( tex_num );
    }
    DX::Shader::PSCode ps_code( "PS_Func", ps_code_frgm );
    buf = ps_code.GetCode();
    m_sp_pxl_shader =
      CPL_MAKE_SHARED( CPixelShader, ps_code, "PS_Func", "ps_4_0", nullptr );

#ifdef CPL_DEBUG
    Core::FileStream
      fileps( SwS("dbg_pixel_shader.txt"),
              Core::FileStream::kWRITE_BINARY );
    fileps << buf;
#endif
  }
  catch(...)
  {
#ifdef CPL_DEBUG
    Core::FileStream
      fileps( SwS("dbg_pixel_shader.txt"),
              Core::FileStream::kWRITE_BINARY );
    fileps << buf;
#endif
  }
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// シェーダー　後始末
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::Shader::Release()
{
}





} // namespace CDI
} // namespace CPL



