Question:
I am making a program that will draw on top of the target window what I need, but when I draw, drawing goes to the wrong coordinates, which I indicated. Moreover, the buffer size for some reason does not correspond to the parameters that I set. So I initialize d2d:
ID2D1Factory* pFactory;
ID2D1HwndRenderTarget* pRenderTarget;
ID2D1SolidColorBrush* ColorBrush;
bool init_render()
{
D2D1_FACTORY_OPTIONS CreateOpt = { D2D1_DEBUG_LEVEL_NONE };
if (S_OK != D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), &CreateOpt, (void**)&pFactory))
{
MessageBox(0, "D2D1CreateFactory", "ERROR", MB_OK | MB_ICONERROR);
return 0;
}
create_canvas();
return 1;
}
void create_canvas()
{
RECT rc;
GetClientRect(targetHWND, &rc);
//std::cout<< rc.right - rc.left <<" "<< rc.bottom - rc.top<<std::endl;
pFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)),//D2D1_RENDER_TARGET_TYPE_DEFAULT
D2D1::HwndRenderTargetProperties(myHWND, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),
&pRenderTarget);
pRenderTarget->CreateSolidColorBrush(color_brush, &ColorBrush);
}
I adjust the size of my window in a loop to the size of the window over which we will draw. Also, in the message handler of my window, I change the buffer size when changing the size of the target window:
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_SIZE:
if (pRenderTarget != NULL)pRenderTarget->Resize(D2D1::SizeU((UINT)LOWORD(lParam), (UINT)HIWORD(lParam)));
return 0;
case WM_SYSCOMMAND:
if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
}
But if you get the size of the buffer, then it is not equal to the sizes that I gave it, more precisely, it is not equal to the size of the target window in pixels:
void rect(float x,float y,float h,float w) {
D2D1_SIZE_F rtSize= pRenderTarget->GetSize();//получаем размер буфера
int width = static_cast<int>(rtSize.width);
int height = static_cast<int>(rtSize.height);
std::cout <<"Render target: "<< width<<" " << height << std::endl;//выводим размер буфера
ColorBrush->SetColor({0.0f,1.0f,0.0f,1.0f});
pRenderTarget->DrawRectangle(D2D1::RectF(x, y, x+h, y+w), ColorBrush,1.0f);//пробуем рисовать по заданным координатам
}
As a result, the buffer is of the wrong size, and the drawing is done in the wrong place. The effect is as if the coordinates (in pixels), where I say to draw one and a half times (approximately) more.
Answer:
Dug around and found the answer. As it turns out, windows uses scaling and when the user sets a value greater than 100%, the system DPI changes. When we create a directx context, it defaults to the system dpi. To set the dpi manually (in my case, I need 100% – this is 96dpi horizontally and vertically, since I have square pixels), you need to set the dpi manually in the ID2D1RenderTarget
interface:
pRenderTarget->SetDpi(96, 96);
Or, during initialization:
pFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),96,96),//D2D1_RENDER_TARGET_TYPE_DEFAULT
D2D1::HwndRenderTargetProperties(cheatEspHWND, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),
&pRenderTarget);
Thanks to @Qwertiy for the suggestive answer.