/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2010/X/X - 2017/02/03
/// 
/// @brief  描画コンポーネント。
/// 
/// ****************************************************************************


#include "../DX/CPL_DX_Exception.h"
#include "../DX/CPL_DX_AutoSaveRenderTargets.h"
#include "CPL_GUC_RenderBox.h"


namespace CPL {
namespace GUC {


//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//// ２の累乗に補正
//int adjust_size_( int size )
//{
//  int value = 1;
//  while( size > value )
//  {
//    value <<= 1;
//  }
//  return value;
//}


// _____________________________________________________________________________
/// @brief コンストラクタ。
/// 
/// @copydoc doxycomment::arg_in_sp_component_for_parent
/// @copydoc doxycomment::arg_in_position_for_component
/// @copydoc doxycomment::arg_in_size_for_component
///   : 0以下の値を渡すと、1として扱います。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RenderBox::RenderBox
( _in<sdptr<Component>> in_sp_component_for_parent
, _in<float2          > in_position_for_component
, _in<float2          > in_size_for_component
) : Container
    ( in_sp_component_for_parent
    , in_position_for_component
    , in_size_for_component
    )
{
  zzz_setFlagCullingChild( true );
  zzf_SetFlag_DrawOwner( true );

  try {
    // アイテム配置用レイヤーコンテナの作成。
    m_sp_layer_item = Factory<Layer>::Create( GetLinkMyself() );

    //
    zzf_setupRenderTarget_
      ( (in_size_for_component.x>0) ? in_size_for_component.x : 1
      , (in_size_for_component.y>0) ? in_size_for_component.y : 1
      );
  }
  catch( DX::ExceptionHR const e )
  {
    CPL_OUTPUT( SwS(" - CPL::GUC::RenderBox::RenderBox()\n") );
    throw;
  }
  catch( ... ) 
  {
    CPL_OUTPUT( SwS("Some errors occurred : - CPL::GUC::RenderBox::RenderBox()\n") );
    throw;
  }
 
  zzf_setupDrawState( false, false, false ); // 描画ステートのデフォルト設定。 
  //zzf_setupDrawState( true, true, true );
  zzf_SetInitializedLevel( zzf_GetClassLevel() );
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RenderBox::RenderBox( cref<RenderBox> in_render_box )
  : td_base( in_render_box )
  , m_render_texture( in_render_box.m_render_texture )
  , m_sp_layer_item
    { FindComponentT_by_UserID<Layer>( in_render_box.m_sp_layer_item )
    }
{
  m_sp_layer_item->SetAutoUserID();
}


// _____________________________________________________________________________
/// @brief デストラクタ。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RenderBox::~RenderBox()
{
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::CreateClone
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  RenderBox::CreateClone
    ( _in<sdptr<Component>> in_sp_component_for_parent
    , _in<float2          > in_offset_position_from_original
    ) const
{
  return
    zzz_CreateClone_Basic<td_self>
      ( in_sp_component_for_parent
      , in_offset_position_from_original
      );
}


// _____________________________________________________________________________
/// @brief レンダリング用テクスチャの作成。
/// 
/// @param[in] in_ptr_d3d_dev : DirectXデバイスのポインタ。
/// @param[in] in_width       : 描画領域の横幅。
/// @param[in] in_height      : 描画領域の縦幅。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  RenderBox::zzf_setupRenderTarget_
    ( _in<float> in_width
    , _in<float> in_height
    )
{
  if( in_width <= 0  ||  in_height <= 0 )
  {
    return;
  }
  const int width  = static_cast<int>(in_width  + 0.999f);
  const int height = static_cast<int>(in_height + 0.999f);

  m_render_texture.Create
    ( width
    , height
    , DXGI_FORMAT_R8G8B8A8_UNORM
    , DXGI_FORMAT_D24_UNORM_S8_UINT
    );

  //// バッファとなるテクスチャの作成
  //DX::CpDXTexture2D cp_BBT; // バックバッファテクスチャ
  //D3D11_TEXTURE2D_DESC desc_BBT;
  //ZeroMemory( &desc_BBT, sizeof(desc_BBT) );
  //desc_BBT.Width              = width;
  //desc_BBT.Height             = height;
  //desc_BBT.MipLevels          = 1;
  //desc_BBT.ArraySize          = 1;
  //desc_BBT.Format             = DXGI_FORMAT_R8G8B8A8_UNORM;
  //desc_BBT.SampleDesc.Count   = 1;
  //desc_BBT.SampleDesc.Quality = 0;
  //desc_BBT.Usage              = D3D11_USAGE_DEFAULT;
  //desc_BBT.BindFlags          = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
  //desc_BBT.CPUAccessFlags     = 0;
  //desc_BBT.MiscFlags          = 0;
  //HRESULT hr =
  //  in_ptr_d3d_dev->CreateTexture2D
  //    ( &desc_BBT
  //    , nullptr
  //    , &cp_BBT
  //    );
  //CPL_THROW_FAILED
  //  ( hr
  //  , "Failed to create a BackBufferTexture.\n"
  //    "CorePLi :  - CPL::GUC::RenderBox::zzf_createRenderTarget_()\n"
  //  );

  //// テクスチャからシェーダーリソースビューを作成
  //DX::CpDXShaderResourceView cp_SRV;
  //in_ptr_d3d_dev->CreateShaderResourceView( cp_BBT, nullptr, &cp_SRV );

  //// テクスチャからレンダリングターゲットビューを作成
  //DX::CpDXRenderTargetView cp_RTV;
  //hr =
  //  in_ptr_d3d_dev->CreateRenderTargetView
  //    ( cp_BBT
  //    , nullptr
  //    , &cp_RTV
  //    );
  //CPL_THROW_FAILED(
  //  hr,
  //  "Failed to create a RenderTargetView.\n"
  //  "CorePLi :  - CPL::GUC::RenderBox::zzf_createRenderTarget_()\n" );


  //// 深度ステンシルバッファ（テクスチャ）を作成
  //DX::CpDXTexture2D cp_DSB;
  //D3D11_TEXTURE2D_DESC desc_DSB;
  //ZeroMemory( &desc_DSB, sizeof(desc_DSB) );
  //desc_DSB.Width              = width;
  //desc_DSB.Height             = height;
  //desc_DSB.MipLevels          = 1;
  //desc_DSB.ArraySize          = 1;
  //desc_DSB.Format             = DXGI_FORMAT_D24_UNORM_S8_UINT;
  //desc_DSB.SampleDesc.Count   = 1;
  //desc_DSB.SampleDesc.Quality = 0;
  //desc_DSB.Usage              = D3D11_USAGE_DEFAULT;
  //desc_DSB.BindFlags          = D3D11_BIND_DEPTH_STENCIL;
  //desc_DSB.CPUAccessFlags     = 0;
  //desc_DSB.MiscFlags          = 0;
  //hr =
  //  in_ptr_d3d_dev->CreateTexture2D
  //    ( &desc_DSB
  //    , nullptr
  //    , &cp_DSB
  //    );
  //CPL_THROW_FAILED
  //  ( hr
  //  , "Failed to create a DepthStencilBuffer.\n"
  //    "CorePLi :  - CPL::GUC::RenderBox::zzf_createRenderTarget_()\n"
  //  );

  //// 深度ステンシルビューの作成
  //DX::CpDXDepthStencilView cp_DSV;
  ////D3D11_DEPTH_STENCIL_VIEW_DESC desc_DSV;
  ////ZeroMemory( &desc_DSV, sizeof(desc_DSV) );
  ////desc_DSV.Format             = desc_DSB.Format;
  ////desc_DSV.ViewDimension      = D3D11_DSV_DIMENSION_TEXTURE2D;
  ////desc_DSV.Texture2D.MipSlice = 0;
  //hr =
  //  in_ptr_d3d_dev->CreateDepthStencilView
  //    ( cp_DSB
  //    , nullptr
  //    , &cp_DSV
  //    );
  //CPL_THROW_FAILED
  //  ( hr
  //  , "Failed to create a DepthStencilView.\n"
  //    "CorePLi :  - CPL::GUC::RenderBox::zzf_createRenderTarget_()\n"
  //  );

  //// 保持するポインタに設定
  //m_cp_render_texture     = cp_SRV;
  //m_cp_render_target_view = cp_RTV;
  //m_cp_depth_stencil_view = cp_DSV;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// レンダリング用テクスチャのリサイズ
// ※ テクスチャが小さい場合、現在のコンテナサイズに調整される
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//bool RenderBox::zzf_resizeRenderTexture_()
//{
//  if( !m_cp_render_target_view )
//  {
//    return false;
//  }
//
//  // 現在のバックバッファサイズを取得
//  DX::DX_RENDER_TARGET_VIEW_DESC desc_RTV;
//  m_cp_render_target_view->GetDesc( &desc_RTV );
//  desc_RTV.
//  D3DSURFACE_DESC desc;
//  m_sp_tex_target->GetDesc( &desc );
//
//  // サイズ比較
//  int w = m_rect.Width();
//  int h = m_rect.Height();
//  if( (int)desc.Width < w  ||  (int)desc.Height < h )
//  {
//    // テクスチャの再作成
//    return zzf_createRenderTarget_();
//  }
//
//  return true;
//}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// レンダリングステートの初期設定（ウィンドウ用）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//bool RenderBox::zzf_initializeRenderState_()
//{
//  DX::DXDevice*  ptr_d3d_dev = sm_ptr_d3ddev();
//
//  if( ptr_d3d_dev )
//  {
//    // シェーダー無効
//    ptr_d3d_dev->SetVertexShader( nullptr );
//    ptr_d3d_dev->SetPixelShader( nullptr );
//    // レンダリングステート
//    ptr_d3d_dev->SetRenderState( D3DRS_CULLMODE,         D3DCULL_NONE ); // カリング無し
//    ptr_d3d_dev->SetRenderState( D3DRS_LIGHTING,         FALSE ); // ライト無効
//    ptr_d3d_dev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
//    ptr_d3d_dev->SetRenderState( D3DRS_SRCBLEND,         D3DBLEND_SRCALPHA );
//    ptr_d3d_dev->SetRenderState( D3DRS_DESTBLEND,        D3DBLEND_INVSRCALPHA );
//    //
////    ptr_d3d_dev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
////    ptr_d3d_dev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
//    // テクスチャ無効化
//    ptr_d3d_dev->SetTexture( 0, nullptr );
//    ptr_d3d_dev->SetTexture( 1, nullptr );
//    ptr_d3d_dev->SetTexture( 2, nullptr );
//    ptr_d3d_dev->SetTexture( 3, nullptr );
//
//    return true;
//  }
//  else
//  {
//    return false;
//  }
//}




// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_Paint
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
float2
  RenderBox::On_Paint
    ( _in<sdptr<Component>> in_sp_draw_owner
    , _in<float2          > in_offset_position_from_parent
    )
{
  if( sm_sp_render_sprite() )
  {
    if( IsUpdate() )
    {
      auto& cp_d3d_IC = DX::Graphics_i_::GetImmediateContext();

      {
        // 既に描画オブジェクトにプールされていたら転送する。
        sm_def_font_mng()->Translate( sm_ptr_d3ddev() );
        sm_def_sprite_mng().Transrate();

        // 現在のレンダリングターゲットを保存
        DX::AutoSaveRenderTargets save_target( cp_d3d_IC, 1 );

        SetupRenderTarget();
        
        float2 const size = GetSize();
        float4 const rt( 0, 0, size.x, size.y );

        // 
        auto sp_owner = GetOwnerWindow();
        if( sp_owner )
        {
          // クライアント描画イベントの呼び出し。
          // ※ 背景とフレームはRenderClient側で呼ばれるので、ここで呼んではいけない。
          //    これは、クライアント領域のみローカルターゲットに書き込まれるためである。
          if( sp_owner->IsDrawClient() )
          {
            sp_owner->On_DrawClient( rt );
          }
        }

        // 子供コンポーネントの描画呼び出し
        zzf_CallChildPaint( GetLinkMyself(), float2{0,0} );
        //
        sm_def_font_mng()->Translate( sm_ptr_d3ddev() );
        sm_def_sprite_mng().Transrate();
      }

      SetUpdated();
    }

    // スクリーン空間への変換
    float4 rt = GetRectCoord();
    MappingPosition( GetBelongComponent( eParentType::Position ), in_sp_draw_owner, (float2_ptr)&rt, 2 );

    CDI::ColorType color(1,1,1, sm_all_applied_draw_alpha() );
    //if( GetLinkEnd() != this->GetLinkMyself() )
    //{
    //  color.a *= sm_all_applied_draw_alpha();
    //}
    
    //// _____________________________________________________________________________
    //// なぜかWindows10 Anniversary update後にスケールがおかしくなったので補正。
    //auto size_client = this->GetSubjectWindow()->GetClientSize();
    //float scale_x = size_client.x / rt.Width();
    //float scale_y = size_client.y / rt.Height();
    //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    sm_sp_render_sprite()->Draw
      ( m_render_texture.GetShaderResourceView()
      , rt.x, rt.y
      , 0.0f, 0.0f
      , static_cast<float>(rt.Width())
      , static_cast<float>(rt.Height())
      , 0.0f
      , color
      //, 0.0f, 0.0f
      //, scale_x
      //, scale_y
      );
    sm_sp_render_sprite()->Transrate();
  }

  return float2{ 0.0f, 0.0f };
}

/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// テクスチャバッファの更新
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void RenderBox::On_Render()
{
  zzf_initializeRenderState_();

  short4 rt( 0, 0, m_rect.Width(), m_rect.Height() );
//  this->Mapping_ClientToScreen( this->GetLinkMyself(), (short2_ptr)&rt, 2 );

  // 
  On_DrawBackground( rt );
  On_DrawFrame( rt );
  On_DrawClient( rt );
  // 子供コンポーネントの描画呼び出し
  zzf_CallChildPaint( GetLinkMyself() );
}
*/


// _____________________________________________________________________________
/// @brief レンダリングターゲットの設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool RenderBox::SetupRenderTarget()
{
  // ターゲット変更
  m_render_texture.ChangeTarget();

  // クリア
  m_render_texture.ClearColor( float4(0,0,0,0) );
  m_render_texture.ClearDepthStencil( 1.0f, 0 );

  // 
  return true;
}



// _____________________________________________________________________________
/// @brief リサイズイベント
/// 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  RenderBox::On_Size( _in<sdptr<Component>> in_sp_component )
{
  if( in_sp_component == this->GetLinkMyself()  &&
      GetInitialized() >= zzf_GetClassLevel() )
  {
    // テクスチャリサイズ。
    float2 size_client = this->GetSize();
    zzf_setupRenderTarget_
      ( size_client.x
      , size_client.y
      );

    Update();
  }

  return eEventReturnID::SendParent_Position;
}



} // namespace GUC
} // namespace CPL

