STed2いじり(22) GDIとDirect2Dの共用

公開:2010-11-28 13:45
更新:2017-09-22 05:39
カテゴリ:windows,direct2d,sted2,c++,audio

結局BitBltまわりは、GDI関数でやることにして、先に進めることにした。 Direct2Dと共用する方法は、

  1. デバイスコンテキストをDirect2Dのレンダーターゲットにする方法
  2. Direct2Dのレンダーターゲットからデバイスコンテキストを取得してGDI関数を使う方法
の2種類ある。
今回は後者の方法を取ることにした。

気を付けないといけないのは、レンダーターゲットを作成するときにGDI互換属性を指定(D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE)をしておかなくてはいけないこと。さらにレンダーターゲットからCreateCompatibleRenderTarget()するときも、GDI互換属性を指定しなくてはいけない。互換ターゲットだからそのその設定も引き継がれるかと思ったのだけれど、引き継がれなかった。 一連のレンダーターゲットの作成コードは次ののようになった。


HRESULT hr = S_OK;
D2D1_SIZE_F s(D2D1::SizeF(fWindowWidth, fWindowHeight));
// HwndRenderTargetの作成
if(!render_target_)
{
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.usage =  D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
THROW_IF_ERR(factory_->CreateHwndRenderTarget(
rtProps,
D2D1::HwndRenderTargetProperties(hwnd_, D2D1::SizeU(fWindowWidth,fWindowHeight),D2D1_PRESENT_OPTIONS_IMMEDIATELY),
&render_target_
));
}
// バックバッファの作成
THROW_IF_ERR(
render_target_->CreateCompatibleRenderTarget(
&s,NULL,NULL,D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE,&text_bitmap_target_));
//text_bitmap_target_->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
THROW_IF_ERR(
render_target_->CreateCompatibleRenderTarget(
&s,NULL,NULL,D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE,&graphics_bitmap_target_[0]));
THROW_IF_ERR
(render_target_->CreateCompatibleRenderTarget
(&s,NULL,NULL,D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE,&graphics_bitmap_target_[1]));
// GDI描画用のレンダーターゲット
THROW_IF_ERR
(text_bitmap_target_->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&text_dc_target_));
THROW_IF_ERR
(graphics_bitmap_target_[0]->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&graphics_dc_target_[0]));
THROW_IF_ERR
(graphics_bitmap_target_[1]->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&text_dc_target_[1]));

実際にGDI関数を使用する部分のコードは下記のような感じ

void CSTedScreenWin32::TextReverse(int in_x, int in_y, int in_width, int in_page)
{
int x,y,w,h;
COLORREF c,b;
int page;
if (!TextToWindowPos(in_x, in_y, &x, &y)) return;
if (!TextToWindowPos(in_width, 0, &w, &h)) return;
h = fTextLineHeight;
switch (in_page) {
case 0: page=2;break;
case 1: page=0;break;
case 2: page=0;break;
case 3: page=2;break;
}
{
sf::begin_draw_bitmap begin(text_bitmaptarget);
{
sf::d2_dc_type dc(new sf::d2_dc(text_dctarget,D2D1_DC_INITIALIZE_MODE_COPY));
::BitBlt(dc, x,y,w,h, dc, x, y, DSTINVERT);
}
THROW_IF_ERR(begin.end_draw());
}
InvalidateRect(x,y,w,h);
}

sf::d2_dc_type はコンストラクタでGetDC()してデストラクタでReleaseDC()するクラス


struct d2_dc {
d2_dc(ID2D1GdiInteropRenderTargetPtr& ptr,D2D1_DC_INITIALIZE_MODE mode) :hdc_(0),ptr_(ptr)
{
hr_ = ptr->GetDC(mode,&hdc_);
};
~d2_dc(){ptr_->ReleaseDC(NULL);};
HDC get() { return hdc_;};
private:
HRESULT hr_;
HDC hdc_;
ID2D1GdiInteropRenderTargetPtr& ptr_;
};
template <typename Holder>
struct device_context
{
explicit device_context(Holder* holder) : holder_(holder){};
~device_context() {}
operator HDC(){return holder_->get();}
private:
boost::scoped_ptr<Holder> holder_;
};
typedef device_context<d2_dc> d2_dc_type;

描画コードのあちこちでGetDC()するのは効率が悪いような気がするのだけれど、とりあえず進めていくことにする。