Direct2D Effectの利用
下記記事にて、ID2D1DeviceContextを利用して楕円を描画するところまで実装しました。
Direct2D導入(ID2D1DeviceContext) - 何でもプログラミング
今回はID2D1DeviceContextで利用できるようになったEffectを実装してみたいと思います。
上記記事で描画した楕円画像に、赤と青を入れ替えるEffectを適用してみます。
記事中に特に説明のない関数は、上記記事を参照してみてください。
Effect作成
既存のEffectを利用して、赤と青を入れ替えるEffectを作成します。
#include <initguid.h> #include <d2d1_1.h> #pragma comment(lib, "d2d1.lib") ComPtr<ID2D1Effect> CreateEffect(ID2D1DeviceContext* context) { ComPtr<ID2D1Effect> effect; AssertHR(context->CreateEffect(CLSID_D2D1ColorMatrix, &effect)); D2D1_MATRIX_5X4_F matrix = D2D1::Matrix5x4F(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); AssertHR(effect->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, matrix)); return effect; }
OffscreenBufferの作成
Effectの入力としてBackBufferは利用できないため、一時描画先としてOffscreenBufferを作成します。
ComPtr<ID2D1Bitmap1> CreateTargetBitmap(ID2D1DeviceContext* context, D2D1_SIZE_U size) { auto prop = D2D1::BitmapProperties1( D2D1_BITMAP_OPTIONS_TARGET, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE) ); ComPtr<ID2D1Bitmap1> bitmap; AssertHR(context->CreateBitmap(size, nullptr, size.width * 4, prop, &bitmap)); return bitmap; }
アプリケーションコード
まずOffscreenBufferに楕円を描画し、次にEffectを適用した結果をBackBufferに描画しています。
サイズが変更された場合は、BackBuffer、OffscreenBuffer共に作り直しています。(BackBufferを解放しておかないと、ResizeBuffersで例外が発生します。)
ComPtr<ID2D1DeviceContext> g_context; ComPtr<IDXGISwapChain1> g_swapChain; ComPtr<ID2D1Bitmap1> g_backBuffer; ComPtr<ID2D1Bitmap1> g_offscreenBuffer; ComPtr<ID2D1Effect> g_effect; LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_PAINT: { g_context->BeginDraw(); g_context->SetTarget(g_offscreenBuffer.Get()); g_context->Clear(D2D1::ColorF(D2D1::ColorF::LightYellow)); // 楕円描画 D2D1_SIZE_F size = g_context->GetSize(); float rx = size.width / 2; float ry = size.height / 2; D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(rx, ry), rx, ry); ComPtr<ID2D1SolidColorBrush> brush; AssertHR(g_context->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Orange), &brush)); g_context->FillEllipse(ellipse, brush.Get()); // Effect適用(赤青いれかえ) g_context->SetTarget(g_backBuffer.Get()); g_effect->SetInput(0, g_offscreenBuffer.Get()); g_context->DrawImage(g_effect.Get()); g_effect->SetInput(0, nullptr); AssertHR(g_context->EndDraw()); g_context->SetTarget(nullptr); DXGI_PRESENT_PARAMETERS params = { 0 }; AssertHR(g_swapChain->Present1(1, 0, ¶ms)); } return 0; case WM_SIZE: g_backBuffer = nullptr; AssertHR(g_swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0)); // サイズ0で、自動でWindowのサイズが設定される g_backBuffer = CreateBackBufferBitmap(g_context.Get(), g_swapChain.Get()); g_offscreenBuffer = CreateTargetBitmap(g_context.Get(), g_backBuffer->GetPixelSize()); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); }
int main() { HWND hwnd = CreateHWND(WndProc); auto dxgiDevice = CreateDXGIDevice(); g_context = CreateD2DContext(dxgiDevice.Get()); g_swapChain = CreateSwapChain(dxgiDevice.Get(), hwnd); g_backBuffer = CreateBackBufferBitmap(g_context.Get(), g_swapChain.Get()); g_offscreenBuffer = CreateTargetBitmap(g_context.Get(), g_backBuffer->GetPixelSize()); g_effect = CreateEffect(g_context.Get()); Run(hwnd); return 0; }