Direct2D 独自Effectの作成
下記の記事にて、Direct2Dの組み込みのEffectを利用してみました。
Direct2D Effectの利用 - 何でもプログラミング
今回は独自のEffectを作成してみたいと思います。
組み込みで用意されているOffset効果を利用して、描画結果をずらしてみます。
本記事は上記記事をベースとしていますので、特に言及のない関数は上記記事を参照してみてください。
独自Effectクラス
ID2D1EffectImplを実装して独自のEffectクラスを作成します。
基本的にはInitialize関数とRegister関数の実装がメインとなります。
#include <initguid.h> #include <d2d1effectauthor.h> DEFINE_GUID(CLSID_MyEffect, ...); // 独自のGUIDを定義してください。 class MyEffect : public ID2D1EffectImpl { public: // ここから3つの関数は、ID2D1EffectImplに必要な関数です。 IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext* pContextInternal, _In_ ID2D1TransformGraph* pTransformGraph) { // Offsetを行う効果(組み込み)の作成&登録 ComPtr<ID2D1OffsetTransform> transform; auto hr = pContextInternal->CreateOffsetTransform(D2D1::Point2L(10, 10), &transform); if (SUCCEEDED(hr)) hr = pTransformGraph->SetSingleTransformNode(transform.Get()); return hr; } IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE changeType) { return S_OK; } IFACEMETHODIMP SetGraph(_In_ ID2D1TransformGraph* pGraph) { return S_OK; } // ここから2つのstatic関数は、このクラスをID2D1Factory1に登録するのに利用します。(関数名は何でも大丈夫です。) static HRESULT Register(_In_ ID2D1Factory1* pFactory) { // 1画像を入力とするEffectの登録 auto xml = L"<?xml version = '1.0'?> " L"<Effect> " L" <Property name='DisplayName' type='string' value='MyEffect' /> " L" <Property name='Author' type='string' value='Author' /> " L" <Property name='Category' type='string' value='Category' /> " L" <Property name='Description' type='string' value='Description' /> " L" <Inputs> " L" <Input name='Source' /> " L" </Inputs> " L"</Effect> " ; return pFactory->RegisterEffectFromString(CLSID_MyEffect, xml, nullptr, 0, CreateEffect); } static HRESULT __stdcall CreateEffect(_Outptr_ IUnknown** ppEffectImpl) { *ppEffectImpl = (ID2D1EffectImpl*)(new MyEffect()); if (*ppEffectImpl == nullptr) return E_OUTOFMEMORY; return S_OK; } // ここからはCOMに必要な関数です。特別な実装はありません。 IFACEMETHODIMP_(ULONG) AddRef() { m_refCount++; return m_refCount; } IFACEMETHODIMP_(ULONG) Release() { m_refCount--; if (m_refCount == 0) delete this; return m_refCount; } IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppOutput) { *ppOutput = nullptr; HRESULT hr = S_OK; if (riid == __uuidof(ID2D1EffectImpl)) *ppOutput = (ID2D1EffectImpl*)this; else if (riid == __uuidof(IUnknown)) *ppOutput = this; else hr = E_NOINTERFACE; if (*ppOutput != nullptr) AddRef(); return hr; } private: LONG m_refCount; MyEffect() : m_refCount(1) {} };
Effectの作成
独自のGUIDでCreateEffectします。
ComPtr<ID2D1Effect> CreateEffect(ID2D1DeviceContext* context)
{
ComPtr<ID2D1Effect> effect;
AssertHR(context->CreateEffect(CLSID_MyEffect, &effect));
return effect;
}
main関数
作成したEffectの登録が追記されています。
ID2D1Factory1を作成した時に同時に登録したほうが簡潔だと思われます。
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()); ComPtr<ID2D1Factory> factory; g_context->GetFactory(&factory); ComPtr<ID2D1Factory1> factory1; AssertHR(factory.As(&factory1)); AssertHR(MyEffect::Register(factory1.Get())); g_effect = CreateEffect(g_context.Get()); Run(hwnd); return 0; }