Microsoft Visual C++ 2010 Express Microsoft DirectX SDK (February 2010) Direct3D 11.0 |
■Direct3D 11.0 スクリーンショット作成 | Prev Top Next |
関連ページ:Direct3D 11.0 初期化 |
|
さて Direct3D 9 のときはオフスクリーンサーフェスを使用して画像ファイルを作成しましたが、Direct3D 11 ではオフスクリーンサーフェスにアクセスできないようです。
少なくともその方法を筆者は知りません。
そのためバックバッファにアクセスしてファイル出力する方法にします。
ここで1点だけ注意することがあります。
ファイル出力には D3DX11SaveTextureToFile() 関数を使用しますが、
スワップチェーンにマルチサンプリングを設定している場合、この関数でエラーになります。
この場合、いったんマルチサンプリングされていないテクスチャーにデータをコピーしてから、ファイル出力する方法をとる必要があります。
この辺のロジックは、Direct3D 11.0 初期化で紹介しているのでそちらをまず参照してください。
っていうか今回のネタはそっちがすべてでこのページで紹介することはほとんどないです。
---main.cpp---
#include "../../USER/DX11User.h" #include "../../USER/D3D11User.h" // コンパイル済み頂点シェーダー #include "../../USER/HLSL/SimpleHLSL03_vs.h" // コンパイル済みピクセルシェーダー #include "../../USER/HLSL/SimpleHLSL03_ps.h" // シェーダーオブジェクトを作成するとき、ファイルから読むか、メモリから読むかを切り替える #if defined(DEBUG) || defined(_DEBUG) #define UNCOMPILED_SHADER // ファイルを読み込んでコンパイルする #endif // アプリケーション名 TCHAR* AppName = _T("DX11_Tutrial04"); // Direct3D関連の自作クラス D3D11USER* g_pD3D11User = NULL; // 頂点バッファ ID3D11Buffer* g_pVertexBuffer = NULL; // インデックスバッファ ID3D11Buffer* g_pIndexBuffer = NULL; // 頂点シェーダー ID3D11VertexShader* g_pVertexShader = NULL; // 入力レイアウト ID3D11InputLayout* g_pLayout = NULL; // ピクセルシェーダー ID3D11PixelShader* g_pPixelShader = NULL; // シェーダーリソースビュー ID3D11ShaderResourceView* g_pSRView = NULL; // サンプラーステート ID3D11SamplerState* g_pSamplerState = NULL; // 頂点定義 struct VERTEX { // 頂点座標 D3DXVECTOR3 pos; // 頂点カラー D3DXCOLOR color; // テクセル D3DXVECTOR2 texel; }; // 節電モードの制御に使用する変数。 bool Activate = true; // ウィンドウがアクティブか bool StandBy = false; // スタンバイ状態か bool ScreenShot = false; // スクリーンショットを作成するかフラグ // リソースの初期化 HRESULT Init() { HRESULT hr = E_FAIL; // D3DX11_IMAGE_LOAD_INFO D3DX11_IMAGE_LOAD_INFO info; // 頂点座標と頂点カラーを設定 VERTEX v[] = { D3DXVECTOR3( 80.0f, 200.0f, 0.0f ), 0xFFFF0000, D3DXVECTOR2( 1.0f, 0.0f ), D3DXVECTOR3( -80.0f, 200.0f, 0.0f ), 0xFF00FF00, D3DXVECTOR2( 0.0f, 0.0f ), D3DXVECTOR3( 80.0f, 10.0f, 0.0f ), 0xFF0000FF, D3DXVECTOR2( 1.0f, 1.0f ), D3DXVECTOR3( -80.0f, 10.0f, 0.0f ), 0xFFFF00FF, D3DXVECTOR2( 0.0f, 1.0f ), }; // 頂点バッファを作成する hr = g_pD3D11User->CreateVertexBuffer( &g_pVertexBuffer, v, sizeof( v ), 0 ); if( FAILED( hr ) ) goto EXIT; // インデックスバッファを設定 UINT Index[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; // インデックスバッファを作成する。 hr = g_pD3D11User->CreateIndexBuffer( &g_pIndexBuffer, Index, sizeof( Index ), 0 ); if( FAILED( hr ) ) goto EXIT; // 頂点シェーダーを作成する D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR" , 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; #ifndef UNCOMPILED_SHADER hr = g_pD3D11User->CreateVertexShaderFromMemory( &g_pVertexShader, g_VS_Main, sizeof( g_VS_Main ), &g_pLayout, layout, _countof( layout ) ); if( FAILED( hr ) ) goto EXIT; #else hr = g_pD3D11User->CreateVertexShaderFromFile( &g_pVertexShader, _T("../../USER/HLSL/SimpleHLSL03.hlsl"), "VS_Main", "vs_4_0", &g_pLayout, layout, _countof( layout ) ); if( FAILED( hr ) ) goto EXIT; #endif // ピクセルシェーダーを作成する #ifndef UNCOMPILED_SHADER hr = g_pD3D11User->CreatePixelShaderFromMemory( &g_pPixelShader, g_PS_Main, sizeof( g_PS_Main ) ); if( FAILED( hr ) ) goto EXIT; #else hr = g_pD3D11User->CreatePixelShaderFromFile( &g_pPixelShader, _T("../../USER/HLSL/SimpleHLSL03.hlsl"), "PS_Main", "ps_4_0" ); if( FAILED( hr ) ) goto EXIT; #endif // ファイルからシェーダーリソースビューを作成する ::ZeroMemory( &info, sizeof( D3DX11_IMAGE_LOAD_INFO ) ); info.Width = D3DX11_DEFAULT; info.Height = D3DX11_DEFAULT; info.Depth = D3DX11_DEFAULT; info.FirstMipLevel = D3DX11_DEFAULT; // テクスチャーの最高解像度のミップマップ レベル。実際の使用方法不明。 info.MipLevels = 0; // ミップマップ数。0 または D3DX11_DEFAULT を使用するとすべてのミップマップ チェーンを作成する。 info.Usage = D3D11_USAGE_DEFAULT; info.BindFlags = D3D11_BIND_SHADER_RESOURCE; info.CpuAccessFlags = 0; info.MiscFlags = 0; info.Format = DXGI_FORMAT_FROM_FILE; info.Filter = D3DX11_FILTER_POINT; // テクスチャー読み込み時に使用するフィルター info.MipFilter = D3DX11_FILTER_POINT; // ミップマップ作成時に使用するフィルター info.pSrcInfo = NULL; hr = D3DX11CreateShaderResourceViewFromFile( g_pD3D11User->m_D3DDevice, _T("res\\01.jpg"), &info, NULL, &g_pSRView, NULL ); if( FAILED( hr ) ) goto EXIT; // サンプラーステートの設定 D3D11_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC; // サンプリング時に使用するフィルタ。ここでは異方性フィルターを使用する。 samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; // 0 〜 1 の範囲外にある u テクスチャー座標の描画方法 samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; // 0 〜 1 の範囲外にある v テクスチャー座標 samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; // 0 〜 1 の範囲外にある w テクスチャー座標 samplerDesc.MipLODBias = 0; // 計算されたミップマップ レベルからのバイアス samplerDesc.MaxAnisotropy = 16; // サンプリングに異方性補間を使用している場合の限界値。有効な値は 1 〜 16 。 samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; // 比較オプション。 ::CopyMemory( samplerDesc.BorderColor, &D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 0.0f ), sizeof( D3DXVECTOR4 ) ); // 境界色 samplerDesc.MinLOD = 0; // アクセス可能なミップマップの下限値 samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; // アクセス可能なミップマップの上限値 hr = g_pD3D11User->m_D3DDevice->CreateSamplerState( &samplerDesc, &g_pSamplerState ); if( FAILED( hr ) ) goto EXIT; hr = S_OK; EXIT: return hr; } // メモリ開放 void Invalidate() { SAFE_RELEASE( g_pSamplerState ); SAFE_RELEASE( g_pSRView ); SAFE_RELEASE( g_pVertexShader ); SAFE_RELEASE( g_pPixelShader ); SAFE_RELEASE( g_pLayout ); SAFE_RELEASE( g_pIndexBuffer ); SAFE_RELEASE( g_pVertexBuffer ); SAFE_DELETE( g_pD3D11User ); } // 描画処理 HRESULT Render() { HRESULT hr = E_FAIL; D3DXMATRIX matWorld, matView, matProj, matWVP; float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // バックバッファをクリア g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pD3D11User->m_RenderTargetView, ClearColor ); // 深度バッファをクリア if( g_pD3D11User->m_DepthStencilView ) g_pD3D11User->m_D3DDeviceContext->ClearDepthStencilView( g_pD3D11User->m_DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 ); // 頂点バッファ設定 UINT stride = sizeof( VERTEX ); UINT offset = 0; g_pD3D11User->m_D3DDeviceContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset ); // インデックスバッファ設定 g_pD3D11User->m_D3DDeviceContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 ); // レイアウト設定 g_pD3D11User->m_D3DDeviceContext->IASetInputLayout( g_pLayout ); // プリミティブ タイプおよびデータの順序に関する情報を設定 g_pD3D11User->m_D3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ); // 行列設定 D3DXMatrixPerspectiveFovLH( &matProj, 3.1415926f / 2.0f, 4.0f / 3.0f, 1.0f, 250.0f ); D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 20.0f, -20.0f ), &D3DXVECTOR3( 0.0f, 20.0f, 0.0f ), &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) ); static float x = 90.0f; D3DXMatrixRotationX( &matWorld, D3DXToRadian( x ) ); matWVP = matWorld * matView * matProj; // シェーダー内では列優先にしているので転置行列を作成する。 D3DXMatrixTranspose( &matWVP, &matWVP ); ID3D11Buffer* Buffers = NULL; // 定数バッファを作成する。 hr = g_pD3D11User->CreateConstantBuffer( &Buffers, NULL, sizeof( D3DXMATRIX ), D3D11_CPU_ACCESS_WRITE ); if( FAILED( hr ) ) goto EXIT; D3D11_MAPPED_SUBRESOURCE mappedResource; // サブリソースに格納されているデータへのポインターを取得して、そのサブリソースへの GPU のアクセスを拒否。 hr = g_pD3D11User->m_D3DDeviceContext->Map( Buffers, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource ); if( FAILED( hr ) ) goto EXIT; ::CopyMemory( mappedResource.pData, &matWVP, sizeof( D3DXMATRIX ) ); g_pD3D11User->m_D3DDeviceContext->Unmap( Buffers, 0 ); // 頂点シェーダーをデバイスに設定する。 g_pD3D11User->m_D3DDeviceContext->VSSetShader( g_pVertexShader, NULL, 0 ); // 頂点シェーダーに定数バッファを設定する。 g_pD3D11User->m_D3DDeviceContext->VSSetConstantBuffers( 0, 1, &Buffers ); // ハルシェーダーを無効にする。 g_pD3D11User->m_D3DDeviceContext->HSSetShader( NULL, NULL, 0 ); // ドメインシェーダーを無効にする。 g_pD3D11User->m_D3DDeviceContext->DSSetShader( NULL, NULL, 0 ); // ジオメトリシェーダーを無効にする。 g_pD3D11User->m_D3DDeviceContext->GSSetShader( NULL, NULL, 0 ); // ピクセルシェーダーをデバイスに設定する。 g_pD3D11User->m_D3DDeviceContext->PSSetShader( g_pPixelShader, NULL, 0 ); g_pD3D11User->m_D3DDeviceContext->PSSetSamplers( 0, 1, &g_pSamplerState ); g_pD3D11User->m_D3DDeviceContext->PSSetShaderResources( 0, 1, &g_pSRView ); // コンピュートシェーダーを無効にする。 g_pD3D11User->m_D3DDeviceContext->CSSetShader( NULL, NULL, 0 ); // インデックスバッファを使用した描画 g_pD3D11User->m_D3DDeviceContext->DrawIndexed( 4, 0, 0 ); // レンダリングされたイメージをユーザーに表示。 hr = g_pD3D11User->m_SwapChain->Present( 0, 0 ); if( ScreenShot ) { // スクリーンショット作成 g_pD3D11User->CreateScreenShot(); ScreenShot = false; } EXIT: SAFE_RELEASE( Buffers ); return hr; } // 節電処理および描画処理 HRESULT PowerSavingAndRender() { HRESULT hr = E_FAIL; switch( StandBy ) { // スタンバイモード case true: // テストのみ行い、描画処理は行わない。 hr = g_pD3D11User->m_SwapChain->Present( 0, DXGI_PRESENT_TEST ); switch( hr ) { // いまだスタンバイ中。。。 case DXGI_STATUS_OCCLUDED: // 電源管理によるスリープ状態の場合ここにくる。 // フルスクリーンモード時にスクリーンセーバーが起動時した場合は、表示モードが強制的にウィンドウモードに変更されるためここにこない。 goto EXIT; break; case S_OK: // フルスクリーンモード時にスクリーンセーバーが起動時した場合は表示モードが強制的にウィンドウモードに変更される。 // ウィンドウモードの場合スタンバイから復帰してしまうため、ウィンドウがアクティブになったときに復帰するようにする。 if( Activate == true ) { // たまにウィンドウが表示されないときがあるので表示するようにする ::ShowWindow( g_pD3D11User->m_hWnd, SW_SHOW ); StandBy = false; } break; default: goto EXIT; break; } break; // スタンバイモードでない case false: // 描画処理 hr = Render(); if( FAILED( hr ) ) goto EXIT; switch( hr ) { case DXGI_STATUS_OCCLUDED: // スタンバイモードへ移行 // フルスクリーンモード時のスクリーンセーバー起動時、 // スリープ状態に移行した時に発生する。 StandBy = true; goto EXIT; break; case S_OK: break; default: goto EXIT; break; } break; } hr = S_OK; EXIT: return hr; } // ウィンドウプロシージャ LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam ) { switch( msg ) { case WM_KEYUP: // アプリ終了 if( wParam == VK_ESCAPE ) ::DestroyWindow( hWnd ); // F2キーを押すと、ウィンドウモードを切り替える。 // 自動的にウィンドウモードを切り替える機能もあるが、ウィンドウスタイルを自由に変更するために自分で実装することにした。 if( wParam == VK_F2 ) { g_pD3D11User->ChangeWindowMode(); } // スクリーンショットを作成する if( wParam == VK_SNAPSHOT ) ScreenShot = true; break; case WM_ACTIVATE: Activate = true; break; // フルスクリーンからウィンドウモードに切り替えるとき WM_SIZE イベントが発生せず、結果的に IDXGISwapChain::ResizeBuffers がコールされない。 // 環境にもよるようだが、画面上に何も表示されない現象が発生する可能性があるので // D3D11USER::ChangeWindowModeOptimization() は D3D11USER::ChangeWindowMode() 内でコールするように修正し、ここでの処理は無効にする // case WM_SIZE: // g_pD3D11User->ChangeWindowModeOptimization(); // break; case WM_DESTROY: Invalidate(); ::PostQuitMessage(0); break; default: return ::DefWindowProc( hWnd, msg, wParam, lParam ); } return 0L; } // メイン関数 int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmpLine*/, INT /*nCmdShow*/ ) { HRESULT hr = E_FAIL; MSG msg; ::ZeroMemory(&msg, sizeof(MSG)); // 表示モードを記述するための構造体。 DXGI_MODE_DESC sd; // Direct3D 関連自作クラスのインスタンスを作成 g_pD3D11User = new D3D11USER(); // ディスプレイモード一覧を取得する。 // 取得した値はクラス内部に保持される。 hr = g_pD3D11User->GetDisplayMode(); if( FAILED( hr ) ) { ::MessageBox( NULL, _T("ディスプレイモード取得エラー"), _T("初期化エラー"), MB_OK ); goto EXIT; } // とりあえず最初に見つかったディスプレイモードを選択する CopyMemory( &sd, &g_pD3D11User->m_DisplayModeDesc[0], sizeof( DXGI_MODE_DESC ) ); // ウィンドウの作成およびDirect3D の初期化 hr = g_pD3D11User->InitD3D11( AppName, hInstance, WndProc, &sd, TRUE, TRUE, TRUE, TRUE ); if( FAILED( hr ) ) { ::MessageBox( NULL, _T("Direct3D 11.0 初期化エラー"), _T("初期化エラー"), MB_OK ); goto EXIT; } // リソースの初期化 hr = Init(); if( FAILED( hr ) ) { ::MessageBox( NULL, _T("リソース初期化エラー"), _T("初期化エラー"), MB_OK ); goto EXIT; } ::ShowWindow(g_pD3D11User->m_hWnd, SW_SHOW); ::UpdateWindow(g_pD3D11User->m_hWnd); // メッセージループ do { if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } else { hr = PowerSavingAndRender(); if( FAILED( hr ) ) ::DestroyWindow( g_pD3D11User->m_hWnd ); } }while( msg.message != WM_QUIT ); EXIT: if( g_pD3D11User && g_pD3D11User->m_hWnd ) ::DestroyWindow( g_pD3D11User->m_hWnd ); ::UnregisterClass( AppName, hInstance ); return msg.wParam; }ソース内で使用している SimpleHLSL03.hlsl はDirect3D 11.0 テクスチャーを使うで使用したファイルをそのまま使用しています。
さてこのサンプルの場合、ウィンドウモードでスクリーンショットを作成すると、タイトルバーやウィンドウ枠が出力されません。 別にそれでも問題ないと思いますが、どうしてもタイトルバーも出力したいという場合、クリップボードを使用すればできないこともないです。 Alt + PrtSc でウィンドウのイメージをクリップボードに転送し、プログラム側でクリップボードに書き込まれているビットマップイメージを参照し、画像出力するようにします。 一応こんな感じになります。
---クリップボードのビットマップを参照し、画像出力するサンプル---
// スナップショット作成 HRESULT D3D11USER::CreateScreenShot() { HRESULT hr = E_FAIL; WCHAR root[] = _T("ScreenShot"); WCHAR path[256]; int maxFileCnt = 20; // ビットマップのバイナリバッファ BYTE* bits = NULL; ID3D11Texture2D* texture = NULL; // SetClipboardViewer を実行すると WM_DRAWCLIPBOARD イベントが実行されてしまうっぽいので // 初期化が完了してないときはスクリーンショットを作成しないようにする。 if( m_D3DDevice == NULL || m_D3DDeviceContext == NULL ) { hr = S_OK; goto EXIT; } OutputMsg( _T("スクリーンショット作成"), _T(""), _T("開始") ); // ScreenShot フォルダがありますか? if( ::PathFileExists( root ) == false ) { // ないので ScreenShotフォルダを作成する if( ::CreateDirectory( root, NULL ) == FALSE ) goto EXIT; } int i = 0; // ファイルを作成しすぎてディスクがパンクすることがないようにするため、ファイルの作成可能数を限定する。 while( i < maxFileCnt ) { _stprintf_s( path, _T("%s\\%02d.jpg"), root, i ); // ファイルがありますか? if( ::PathFileExists( path ) == FALSE ) break; i++; } // スクリーンショットの作成可能数をオーバーしているため作成できません。 if( i >= maxFileCnt ) { OutputMsg( _T("スクリーンショット作成"), _T(""), _T("作成数オーバー") ); goto EXIT; } // クリップボードに存在するデータがビットマップか if( ::IsClipboardFormatAvailable( CF_BITMAP ) ) { // クリップボードのオープン if( !::OpenClipboard( m_hWnd ) ) goto EXIT; HBITMAP hBitmap = NULL; // GetClipboardData if( ( hBitmap = (HBITMAP)::GetClipboardData(CF_BITMAP) ) == NULL ) goto EXIT; // BITMAP 構造体を作成する BITMAP bitmap; ::GetObject(hBitmap, sizeof(BITMAP), &bitmap); // ファイルヘッダ部 // BITMAPFILEHEADER BITMAPFILEHEADER bHeader; ::ZeroMemory( &bHeader, sizeof( BITMAPFILEHEADER ) ); // BM 固定 bHeader.bfType = ('M'<<8) + 'B'; // ファイルサイズ bHeader.bfSize = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + bitmap.bmWidth * bitmap.bmHeight * bitmap.bmBitsPixel; // ファイル先頭から画像データまでのオフセット bHeader.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ); // 情報ヘッダ部 // BITMAPINFO // BITMAPINFOHEADER BITMAPINFO info; ::ZeroMemory(&info, sizeof(BITMAPINFO)); info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); info.bmiHeader.biWidth = bitmap.bmWidth; info.bmiHeader.biHeight = bitmap.bmHeight; info.bmiHeader.biPlanes = 1; // 常に 1 info.bmiHeader.biBitCount = bitmap.bmBitsPixel; // 1 ピクセルあたりのビット数を指定する。ディスプレイのカラービット深度に依存する。 info.bmiHeader.biCompression = BI_RGB; // 非圧縮 bits = new BYTE[bHeader.bfSize]; // ファイルヘッダ部をコピー CopyMemory( bits, &bHeader, sizeof( BITMAPFILEHEADER ) ); // 情報ヘッダ部をコピー(カラーテーブルは作成しない) CopyMemory( &bits[sizeof( BITMAPFILEHEADER )], &info, sizeof( BITMAPINFOHEADER ) ); HDC hDC = NULL; hDC = GetDC( m_hWnd ); // 指定されたビットマップのビットを取得し、指定された形式でバッファへコピーする。 // GetDIBits GetDIBits( hDC, // デバイスコンテキスト hBitmap, // ビットマップハンドル 0, // 取得する最初の走査行 bitmap.bmHeight, // 取得する走査行の数 &bits[sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER )], // 保存するバッファのポインタ &info, // BITMAPINFO構造体のポインタ DIB_RGB_COLORS // カラーテーブルを取得しない ); ReleaseDC(NULL, hDC); // システム メモリー内にあるバイナリバッファからテクスチャー リソースを作成する。 // D3DX11CreateTextureFromMemory hr = D3DX11CreateTextureFromMemory( m_D3DDevice, bits, bHeader.bfSize, NULL, NULL, (ID3D11Resource**)&texture, NULL ); if( FAILED( hr ) ) goto EXIT; // ウィンドウモードのとき、画像をウィンドウにあわせてくりぬく // ファイル出力 // D3DX11SaveTextureToFile hr = D3DX11SaveTextureToFile( m_D3DDeviceContext, texture, D3DX11_IFF_JPG, path ); if( FAILED( hr ) ) goto EXIT; OutputMsg( _T("スクリーンショット作成"), path, _T("完了") ); } hr = S_OK; EXIT: ::CloseClipboard(); SAFE_RELEASE( texture ); SAFE_DELETE_ARRAY( bits ); return hr; }自作のクラス D3D11USER::CreateScreenShot の修正版です。まあこのソースは、参考程度に考えてください。 ちなみにビットマップの仕様については近藤正芳のウェブページを参照するとよいです。 大変、詳しく説明されています。
この方法を採用しなかったのは、フルスクリーン時の場合、画像が真っ黒になるからです。ネットで調べたところ、この現象はどうも DirectX の仕様らしいです。 まあウィンドウモードとフルスクリーンとで処理を分岐させればいいのですが、簡単に実装できる方法を選択してDirect3D 11.0 初期化のようにしました。
今回はここまで。次回はフォントかな。いくつか方法があるようだが...