/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/12/06
/// 
/// @brief  グラフィックパイプライン関連
/// 
/// ****************************************************************************


#include "CPL_DX_Kernel.h"
#include "CPL_DX_Pipeline.h"
#include "CPL_DX_Buffer.h"

namespace CPL {
namespace DX {

namespace doxycomment {

/// @param[in] in_ptr_dx_devct
///   : DirectXデバイスコンテキストのアドレスを指定します。\n
void pipeline_arg_in_ptr_dx_devct( _in<DXDeviceContext*> in_ptr_dx_devct ){}
/// @param[in] in_ptr_buffer
///   : バッファオブジェクトのアドレスを指定します。\n
///   : ここで渡すバッファオブジェクトはBuffer::BaseBuffer_の派生クラスとなります。\n
void pipeline_arg_in_ptr_buffer(_in<RenderFragment_i_*> in_ptr_buffer){}
/// @param[in] in_slot_No
///   : バインドに使用する最初の入力スロットを指定します。\n
void pipeline_arg_in_slot_No(_in<int> in_slot_No){}

/// @copydoc CPL::DX::doxycomment::pipeline_arg_in_ptr_dx_devct
/// @copydoc CPL::DX::doxycomment::pipeline_arg_in_ptr_buffer
/// @copydoc CPL::DX::doxycomment::pipeline_arg_in_slot_No
void pipeline_args
      ( _in<DXDeviceContext*> in_ptr_dx_devct
      , _in<RenderFragment_i_*> in_ptr_buffer
      , _in<int> in_slot_No
      ){}
}


// _____________________________________________________________________________
/// @brief インプットアセンブラ用パイプラインコネクタ
/// 
/// @copydoc CPL::DX::doxycomment::pipeline_args
///   : 渡されたバッファが頂点バッファの場合のみ有効です。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  Pipeline::InputAssembler
    ( _in<DXDeviceContext*  > in_ptr_dx_devct
    , _in<RenderFragment_i_*> in_ptr_buffer
    , _in<int               > in_slot_No
    )
{
  // メンバインスタンス取得のため、Buffer::BaseBuffer_にキャスト
  Buffer::BaseBuffer_*
    ptr_buffer =
      static_cast<Buffer::BaseBuffer_*>( in_ptr_buffer );
  // バインドタイプを取得
  UINT bind_flag = ptr_buffer->GetBindFlags();
  // Direct3Dバッファに変換
  DX::DXBuffer* ptr_dx_buffer_tbl[] = { ptr_buffer->GetDxObject() };

  switch( bind_flag )
  {
  case D3D11_BIND_VERTEX_BUFFER:
    {
      //
      UINT element_size = static_cast<UINT>(ptr_buffer->GetElementSize());
      UINT offs = 0;
      in_ptr_dx_devct->IASetVertexBuffers
        ( in_slot_No
        , 1, ptr_dx_buffer_tbl
        , &element_size
        , &offs
        );
    }
    break;

  case D3D11_BIND_INDEX_BUFFER:
    in_ptr_dx_devct->IASetIndexBuffer
      ( ptr_dx_buffer_tbl[0]
      , DXGI_FORMAT_R32_UINT
      , 0
      );
    break;
  }
}


// _____________________________________________________________________________
/// @brief 頂点シェーダー用パイプラインコネクタ
/// 
/// @copydoc CPL::DX::doxycomment::pipeline_args
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  Pipeline::VertexShader
    ( _in<DXDeviceContext*  > in_ptr_dx_devct
    , _in<RenderFragment_i_*> in_ptr_buffer
    , _in<int               > in_slot_No
    )
{
  // メンバインスタンス取得のため、Buffer::BaseBuffer_にキャスト
  Buffer::BaseBuffer_*
    ptr_buffer =
      static_cast<Buffer::BaseBuffer_*>( in_ptr_buffer );
  // Direct3Dバッファに変換
  DX::DXBuffer* ptr_dx_buffer = ptr_buffer->GetDxObject();
  // バインドタイプを取得
  UINT bind_flag = ptr_buffer->GetBindFlags();

  //
  switch( bind_flag )
  {
  case D3D11_BIND_CONSTANT_BUFFER:
    in_ptr_dx_devct->VSSetConstantBuffers( in_slot_No, 1, &ptr_dx_buffer );
    break;

  case D3D11_BIND_SHADER_RESOURCE:
    {
      DXShaderResourceView* ptr_shader_RV;
      UINT size = 0;
      ptr_dx_buffer->GetPrivateData(
        __uuidof(DXShaderResourceView),
        &size,
        (void*)&ptr_shader_RV );
      in_ptr_dx_devct->VSSetShaderResources( in_slot_No, 1, &ptr_shader_RV );
    }
    break;
  }
}


// _____________________________________________________________________________
/// @brief ハルシェーダパイプライン
/// 
/// @copydoc CPL::DX::doxycomment::pipeline_args
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  Pipeline::HullShader
    ( _in<DXDeviceContext*  > in_ptr_dx_devct
    , _in<RenderFragment_i_*> in_ptr_buffer
    , _in<int               > in_slot_No
    )
{
  // メンバインスタンス取得のため、Buffer::BaseBuffer_にキャスト
  Buffer::BaseBuffer_*
    ptr_buffer =
      static_cast<Buffer::BaseBuffer_*>( in_ptr_buffer );
  // Direct3Dバッファに変換
  DX::DXBuffer* ptr_dx_buffer = ptr_buffer->GetDxObject();
  // バインドタイプを取得
  UINT bind_flag = ptr_buffer->GetBindFlags();

  //
  switch( bind_flag )
  {
  case D3D11_BIND_CONSTANT_BUFFER:
    in_ptr_dx_devct->HSSetConstantBuffers( in_slot_No, 1, &ptr_dx_buffer );
    break;

  case D3D11_BIND_SHADER_RESOURCE:
    {
      DXShaderResourceView* ptr_shader_RV;
      UINT size = 0;
      ptr_dx_buffer->GetPrivateData(
        __uuidof(DXShaderResourceView),
        &size,
        (void*)&ptr_shader_RV );
      in_ptr_dx_devct->HSSetShaderResources( in_slot_No, 1, &ptr_shader_RV );
    }
    break;
  }
}


// _____________________________________________________________________________
/// @brief ドメインシェーダー用
/// 
/// @copydoc CPL::DX::doxycomment::pipeline_args
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Pipeline::DommainShader
( _in<DXDeviceContext*  > in_ptr_dx_devct
, _in<RenderFragment_i_*> in_ptr_buffer
, _in<int               > in_slot_No
)
{
  // メンバインスタンス取得のため、Buffer::BaseBuffer_にキャスト
  Buffer::BaseBuffer_*
    ptr_buffer =
      static_cast<Buffer::BaseBuffer_*>( in_ptr_buffer );
  // Direct3Dバッファに変換
  DX::DXBuffer* ptr_dx_buffer = ptr_buffer->GetDxObject();
  // バインドタイプを取得
  UINT bind_flag = ptr_buffer->GetBindFlags();

  switch( bind_flag )
  {
  case D3D11_BIND_CONSTANT_BUFFER:
    in_ptr_dx_devct->DSSetConstantBuffers( in_slot_No, 1, &ptr_dx_buffer );
    break;

  case D3D11_BIND_SHADER_RESOURCE:
    {
      DXShaderResourceView* ptr_shader_RV;
      UINT size = 0;
      ptr_dx_buffer->GetPrivateData(
        __uuidof(DXShaderResourceView),
        &size,
        (void*)&ptr_shader_RV );
      in_ptr_dx_devct->DSSetShaderResources( in_slot_No, 1, &ptr_shader_RV );
    }
    break;
  }
}


// _____________________________________________________________________________
/// @brief ジオメトリシェーダー用
/// 
/// @copydoc CPL::DX::doxycomment::pipeline_args
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Pipeline::GeometoryShader
  ( _in<DXDeviceContext*  > in_ptr_dx_devct
  , _in<RenderFragment_i_*> in_ptr_buffer
  , _in<int               > in_slot_No
  )
{
  // メンバインスタンス取得のため、Buffer::BaseBuffer_にキャスト
  Buffer::BaseBuffer_*
    ptr_buffer =
      static_cast<Buffer::BaseBuffer_*>( in_ptr_buffer );
  // Direct3Dバッファに変換
  DX::DXBuffer* ptr_dx_buffer = ptr_buffer->GetDxObject();
  // バインドタイプを取得
  UINT bind_flag = ptr_buffer->GetBindFlags();

  switch( bind_flag )
  {
  case D3D11_BIND_CONSTANT_BUFFER:
    in_ptr_dx_devct->GSSetConstantBuffers( in_slot_No, 1, &ptr_dx_buffer );
    break;

  case D3D11_BIND_SHADER_RESOURCE:
    {
      DXShaderResourceView* ptr_shader_RV;
      UINT size = 0;
      ptr_dx_buffer->GetPrivateData(
        __uuidof(DXShaderResourceView),
        &size,
        (void*)&ptr_shader_RV );
      in_ptr_dx_devct->GSSetShaderResources( in_slot_No, 1, &ptr_shader_RV );
    }
    break;
  }
}


// _____________________________________________________________________________
/// @brief ピクセルシェーダ用
/// 
/// @copydoc CPL::DX::doxycomment::pipeline_args
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Pipeline::PixelShader
  ( _in<DXDeviceContext*  > in_ptr_dx_devct
  , _in<RenderFragment_i_*> in_ptr_buffer
  , _in<int               > in_slot_No
  )
{
  // メンバインスタンス取得のため、Buffer::BaseBuffer_にキャスト
  Buffer::BaseBuffer_*
    ptr_buffer =
      static_cast<Buffer::BaseBuffer_*>( in_ptr_buffer );
  // Direct3Dバッファに変換
  DX::DXBuffer* ptr_dx_buffer = ptr_buffer->GetDxObject();
  // バインドタイプを取得
  UINT bind_flag = ptr_buffer->GetBindFlags();

  switch( bind_flag )
  {
  case D3D11_BIND_CONSTANT_BUFFER:
    in_ptr_dx_devct->PSSetConstantBuffers( in_slot_No, 1, &ptr_dx_buffer );
    break;

  case D3D11_BIND_SHADER_RESOURCE:
    {
      DXShaderResourceView* ptr_shader_RV;
      UINT size = 0;
      ptr_dx_buffer->GetPrivateData(
        __uuidof(DXShaderResourceView),
        &size,
        (void*)&ptr_shader_RV );
      in_ptr_dx_devct->PSSetShaderResources( in_slot_No, 1, &ptr_shader_RV );
    }
    break;
  }
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 出力結合ステージ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//void Pipeline::OutputMerger(
//    DXDeviceContext*    in_ptr_dx_devct, 
//    RenderFragment_i_* in_ptr_buffer,
//    int                 in_slot_No )
//{
//  // 未対応
//}

} // namespace DX
} // namespace CPL