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


#include "CPL_CDI_MeshData.h"


namespace CPL {
namespace CDI {



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// テクスチャデータ構築関数のパス作成ヘルパ関数 文字コード別用テンプレート
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class CHAR_TYPE>
void
  zzf_setupData_by_File_to_MakePath_T
    ( CHAR_TYPE*                        out_tex_path
    , MFI_CommonTexture const*          in_ptr_mesh_info_com_texture
    , Core::String_X_<CHAR_TYPE> const& in_file_path
    );

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// パス作成ヘルパ関数　UNICODE仕様
template<>
void
  zzf_setupData_by_File_to_MakePath_T<wchar_t>
    ( wchar_t*                        out_tex_path
    , MFI_CommonTexture const*        in_ptr_mesh_info_com_texture
    , Core::String_X_<wchar_t> const& in_file_path
    )
{
  // 現在のカレントディレクトリを取得
  wchar_t old_current_path[ _MAX_PATH + 1 ] = { 0 };
  if( ::_wfullpath( old_current_path, L"", _MAX_PATH ) == nullptr )
  {
    return;
  }
  // カレントディレクトリの変更
  Core::StringW file_dir(in_file_path);
  file_dir.FindEndFront( file_dir, '\\', true );
  if( ::_wchdir( file_dir ) != 0 )
  {
    return;
  }
  // 相対パスを絶対パスに変換
  if( ::_wfullpath
        ( out_tex_path
        , Core::ChangeCodeStrings<Core::StringW>
            ( Core::StringA(in_ptr_mesh_info_com_texture->m_path)
            )
        , _MAX_PATH
        ) == nullptr )
  {
    out_tex_path[0] = 0;
    return;
  }
  // カレントディレクトリを元に
  ::_wchdir( old_current_path );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// パス作成ヘルパ関数　マルチバイト仕様
template<>
void
  zzf_setupData_by_File_to_MakePath_T<char>
    ( char*                        out_tex_path
    , MFI_CommonTexture const*     in_ptr_mesh_info_com_texture
    , Core::String_X_<char> const& in_file_path
    )
{
  // 現在のカレントディレクトリを取得
  char old_current_path[ _MAX_PATH + 1 ] = { 0 };
  if( ::_fullpath( old_current_path, "", _MAX_PATH ) == nullptr )
  {
    return;
  }
  // カレントディレクトリの変更
  Core::StringA file_dir(in_file_path);
  file_dir.FindEndFront( file_dir, '\\', true );
  if( ::_chdir( file_dir ) != 0 )
  {
    return;
  }
  // 相対パスを絶対パスに変換
  if( ::_fullpath(
          out_tex_path,
          in_ptr_mesh_info_com_texture->m_path,
          _MAX_PATH ) == nullptr )
  {
    out_tex_path[0] = 0;
    return;
  }

  // カレントディレクトリを元に
  ::_chdir( old_current_path );
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// テクスチャ　データ構築　文字コード別用ヘルパ関数
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  MeshData::Texture::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
    , _in<Core::String       > in_file_path
    )
{
  m_ptr_texture = nullptr;

  char_cptr ptr_data_addr = reinterpret_cast<char_cptr>(in_ptr_chunk);
  MFI_baseTexture const*
    ptr_mesh_info_texture =
      reinterpret_cast<MFI_baseTexture const*>(ptr_data_addr);
  // データポインタ登録
  io_table_for_data_pointer.Add
    ( ptr_mesh_info_texture->m_GID
    , this->GetLinkMyself()
    );
  // チャンクポインタ登録
  io_table_for_chunk_pointer.Add( this, in_ptr_chunk );
  //
  if( ptr_mesh_info_texture->m_tex_type == 0 ) // 共通テクスチャ
  {
    MFI_CommonTexture const*
      ptr_mesh_info_com_texture =
        static_cast<MFI_CommonTexture const*>(ptr_mesh_info_texture);
    // パスの作成
    str_type tex_path[ _MAX_PATH + 1 ] = { 0 };
    zzf_setupData_by_File_to_MakePath_T<str_type>
      ( tex_path
      , ptr_mesh_info_com_texture
      , in_file_path
      );

    // テクスチャ作成
    ID3D11Resource* ptr_tex_resource;
#ifdef CPL_USE_DX11ex
    HRESULT hr =
      DirectX::CreateDDSTextureFromFile
        ( in_ptr_d3d_dev
        , Core::ChangeCodeStrings<Core::StringW>( tex_path )
        , &ptr_tex_resource
        , nullptr
        );
#else
    HRESULT hr =
      D3DX11CreateTextureFromFile
        ( in_ptr_d3d_dev
        , tex_path
        , nullptr
        , nullptr
        , &ptr_tex_resource
        , nullptr
        );
#endif
    if( FAILED(hr) )
    {
      CPL_THROW_CODE
        ( static_cast<int>(eErrorCode::NotCreateTexture)
        , "テクスチャの作成に失敗（共通テクスチャ）\n"
        );
    }
    m_ptr_texture = static_cast<ID3D11Texture2D*>(ptr_tex_resource);
  }
  else // 組み込みテクスチャ
  {
    MFI_BuiltInTexture const*
      pBuiltInTex =
        static_cast<MFI_BuiltInTexture const*>(ptr_mesh_info_texture);
    ID3D11Resource* ptr_tex_resource;
#ifdef CPL_USE_DX11ex
    HRESULT hr =
      DirectX::CreateDDSTextureFromMemory
        ( in_ptr_d3d_dev
        , reinterpret_cast<U8_cptr>(pBuiltInTex->m_buffer)
        , pBuiltInTex->m_tex_size
        , &ptr_tex_resource
        , nullptr  // texture view(shader resource view)
        );

#else
    HRESULT hr =
      D3DX11CreateTextureFromMemory
        ( in_ptr_d3d_dev
        , pBuiltInTex->m_buffer
        , pBuiltInTex->m_tex_size
        , nullptr
        , nullptr
        , &ptr_tex_resource
        , nullptr
        );
#endif
    if( FAILED(hr) )
    {
      CPL_THROW_CODE
        ( static_cast<int>(eErrorCode::NotCreateTexture)
        , "テクスチャの作成に失敗（プライベートテクスチャ）\n"
        );
    }
    m_ptr_texture = static_cast<ID3D11Texture2D*>(ptr_tex_resource);
  }
}


// _____________________________________________________________________________
/// @brief Texture コピーコンストラクタ
/// 
/// @param[in] in_texture : コピー元のTextureオブジェクトを指定してください。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::Texture::Texture( cref<Texture> in_texture )
  : td_base( in_texture )
  , m_ptr_texture( in_texture.m_ptr_texture )
{
  m_ptr_texture->AddRef();
}


// _____________________________________________________________________________
/// @brief Texture コピーコンストラクタ
/// 
/// @param[in] in_texture : ムーブ元のTextureオブジェクトを指定してください。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MeshData::Texture::Texture( rvref<Texture> in_texture )
  : td_base( std::move(in_texture) )
  , m_ptr_texture( in_texture.m_ptr_texture )
{
  in_texture.m_ptr_texture = nullptr;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// テクスチャ　デストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MeshData::Texture::Release()
{
  CPL_SAFE_PTR(m_ptr_texture)->Release();
}




} // namespace CDI
} // namespace CPL



