結局BitBltまわりは、GDI関数でやることにして、先に進めることにした。 Direct2Dと共用する方法は、
の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()するのは効率が悪いような気がするのだけれど、とりあえず進めていくことにする。