c - 带有 C.FillRectangle 的 Direct2D 不工作

标签 c visual-studio winapi directx

我目前正在为一个业余项目重新学习 C,为此我正在尝试使用 direct2D 图形构建一个简单的 UI。使用 DirectX in C 上提供的说明,我能够成功打开一个空白窗口。因为我的 UI 只需要几个矩形,所以我没有在该教程中使用 Direct3D 代码。相反,我正在尝试使用 Direct2D API 绘制一个填充的矩形,但它不起作用。我已经多次检查每一行代码并尝试了很多东西,但就是无法让它工作。下面粘贴了我完整的 C 文件。

在我的 render() 函数中, ID2D1HwndRenderTarget_Clear(window->renderTarget, &whiteColor); 似乎有效,但 FillRectangle 无效。有人可以告诉我,如何解决这个问题吗?

#include <windows.h>
#include <malloc.h>

#include <d2d1.h>
#pragma comment(lib, "d2d1.lib")

const int WIDTH = 400;
const int HEIGHT = 400;

typedef struct {
    HWND hWnd;
    BOOL bDone;

    ID2D1Factory* direct2dFactory;
    ID2D1HwndRenderTarget* renderTarget;
    ID2D1SolidColorBrush* m_pLightSlateGrayBrush;
    ID2D1SolidColorBrush* m_pCornflowerBlueBrush;
} WindowObject;

static LRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static void FreeWindowObject(WindowObject *window);

HRESULT CreateDeviceIndependentResources(WindowObject *window)
{
    HRESULT hr = S_OK;
    ID2D1Factory* pFactory = NULL;
    const D2D1_FACTORY_OPTIONS opts = { D2D1_DEBUG_LEVEL_INFORMATION };
    // Create a Direct2D factory.
    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, 
        &IID_ID2D1Factory, &opts, (void**)&pFactory);
    window->direct2dFactory = pFactory;

    return hr;
}


HRESULT CreateDeviceResources(WindowObject *window)
{
    HRESULT hr = S_OK;

    if (!window->renderTarget)
    {
        RECT rc;
        GetClientRect(window->hWnd, &rc);

        D2D1_SIZE_U size;
        size.width = rc.right - rc.left;
        size.height = rc.bottom - rc.top;

        D2D1_RENDER_TARGET_PROPERTIES renderProps;
        D2D1_HWND_RENDER_TARGET_PROPERTIES hwndRenderProps;
        D2D1_PIXEL_FORMAT pixFmt = { DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_UNKNOWN };
        renderProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
        renderProps.pixelFormat = pixFmt;
        renderProps.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
        renderProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
        renderProps.dpiX = renderProps.dpiY = 0.f;

        hwndRenderProps.hwnd = window->hWnd;
        hwndRenderProps.pixelSize = size;
        hwndRenderProps.presentOptions = D2D1_PRESENT_OPTIONS_NONE;

        // Create a Direct2D render target.
        if (FAILED(hr = ID2D1Factory_CreateHwndRenderTarget(window->direct2dFactory, 
            &renderProps, &hwndRenderProps, &window->renderTarget)))
        {
            OutputDebugStringA("Failed to create render target, err = %#x\n", hr);
            return 0;
        }

        D2D1_COLOR_F redColor = { 51, 51, 255 };
        if (SUCCEEDED(hr))
        {
            // Create a gray brush.
            hr = ID2D1HwndRenderTarget_CreateSolidColorBrush(window->renderTarget,
                &redColor, NULL, &window->m_pLightSlateGrayBrush);
        }
    }

    return hr;
}


void DiscardDeviceResources(WindowObject *window)
{
    ID2D1HwndRenderTarget_Release(window->renderTarget);
    ID2D1Factory_Release(window->direct2dFactory);
    //ID2D1HwndRenderTarget_Release(window->m_pCornflowerBlueBrush);
    //ID2D1HwndRenderTarget_Release(window->m_pLightSlateGrayBrush);
}


static WindowObject *CreateWindowObject(HINSTANCE hInstance)
{
    WindowObject *window;
    // Allocate the window data and create the window.
    window = malloc(sizeof(WindowObject));
    ZeroMemory(window, sizeof(WindowObject));
    HRESULT hr = CreateDeviceIndependentResources(window);

    const char *name = "Simple";
    int x, y, width, height;
    RECT rect;
    DWORD dwStyle = WS_VISIBLE | WS_OVERLAPPEDWINDOW;
    DWORD dwExStyle =  WS_EX_CLIENTEDGE;
    WNDCLASS wndClass = {
        CS_HREDRAW | CS_VREDRAW, WinProc, 0, 0, hInstance,
        0, LoadCursor(0, IDC_ARROW),
        1, 0, name
    };
    RegisterClass(&wndClass);

    window->hWnd = CreateWindowEx(
        dwExStyle, name, name, dwStyle,
        CW_USEDEFAULT,
        CW_USEDEFAULT, WIDTH, HEIGHT,
        0, 0, hInstance, 0
    );

    SetWindowLongPtr(window->hWnd, GWLP_USERDATA, window);

    hr = window->hWnd ? S_OK : E_FAIL;
    return window;
}

HRESULT render(WindowObject *window)
{
    HRESULT hr = S_OK;
    hr = CreateDeviceResources(window);
    if (!SUCCEEDED(hr))
    {
        return hr;
    }
    ID2D1HwndRenderTarget_BeginDraw(window->renderTarget);

    D2D1_COLOR_F whiteColor = { 255, 255,255 };
    ID2D1HwndRenderTarget_Clear(window->renderTarget, &whiteColor);

        // Draw rectangle.
    D2D1_RECT_F rectangle1 = { 10, 10,100,100 };
    ID2D1HwndRenderTarget_FillRectangle(window->renderTarget, &rectangle1, window->m_pLightSlateGrayBrush);

    hr = ID2D1HwndRenderTarget_EndDraw(window->renderTarget, NULL, NULL);
    if (hr == D2DERR_RECREATE_TARGET)
    {
        hr = S_OK;
        DiscardDeviceResources(window);
    }
    return hr;
}



static LRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    WindowObject *window = (WindowObject *)GetWindowLongPtr(hWnd, GWLP_USERDATA);

    switch (uMsg) {
    case WM_KEYUP:
        if (wParam == VK_ESCAPE)
            SendMessage(hWnd, WM_CLOSE, 0, 0);
        break;
    case WM_PAINT:
        render(window);
        ValidateRect(hWnd, NULL);
        return 0;
        break;
    case WM_CLOSE:
        window->bDone = TRUE;
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WindowObject *window = CreateWindowObject(hInstance);


    while (!window->bDone) {
        MSG msg;
        if (PeekMessage(&msg, window->hWnd, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else {
            render(window);
            ValidateRect(window->hWnd, NULL);
        }
    }

    FreeWindowObject(window);
    return 0;
}

static void FreeWindowObject(WindowObject *window)
{
    DiscardDeviceResources(window);
    free(window);
}

最佳答案

        D2D1_COLOR_F redColor = { 51, 51, 255 };

请记住,D2D1_COLOR_F 是 RGBA,而不是 RGB。所以这会初始化一个 alpha 值为 0 的颜色,它是完全透明的。如果你想要一个完全不透明的矩形,你需要这样说:

        D2D1_COLOR_F redColor = { 51, 51, 255, 255 };

但仍然不正确,因为 D2D1_COLOR_F 的字段是 [0, 1] 范围内的 float (_F)。因此,您需要做的是将 51.0/255.0 替换为 51 并将 1.0 替换为 255:

        D2D1_COLOR_F redColor = { 51.0 / 255.0, 51.0 / 255.0, 1.0, 1.0 };

现在你的矩形应该出现了。

请务必阅读 the documentation ;它解释了一切(即使您必须点击一些 typedef 才能到达那里)。

关于c - 带有 C.FillRectangle 的 Direct2D 不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37357066/

相关文章:

visual-studio - 从 Visual Studio 2022(MAUI、Xamarin)到 macOS 的连接失败

c++ - LNK2019 : unresolved external symbol - no template classes

java - 使用 Java JNA 捕获 Win32 事件

windows - 在 Win32 C API 中执行 `EnumWindows` 查找窗口时如何避免使用全局变量?

c - WriteProcessMemory 不适用于非静态变量

C 中的 CreateProcess 失败

c - 函数中全局变量的malloc和realloc

c - C 中 float 的基数排序 - 负值被破坏

c - 我的代码无法正常运行

visual-studio - Windows窗体设计器: Could not load file or assembly