Как создать ID2D1Bitmap из массива пикселей

Я пытаюсь создать Raycaster с DirectX, и мне нужно иметь возможность рисовать каждый кадр попиксельно. Я пытаюсь сделать это, создав массив пикселей, а затем превратив этот массив в растровое изображение, чтобы затем отобразить его в окне. Однако я не могу понять, как это сделать.

В прошлой версии, которая просто использовала стандартный API Win32 без DirectX, я использовал метод отсюда: Как отображать пиксели на экране непосредственно из необработанного массива значений RGB быстрее, чем SetPixel()?

Однако теперь, когда я использую DirectX, это больше не работает. На самом деле ни одна из команд рисования Win32 (например, Rectangle) не работает. Работают только команды DirectX (думаю, потому что я использую PeekMessage вместо GetMessage и не жду сообщения WM_PAINT).

Так что кажется, что мне нужно найти DirectX-эквивалент этого ответа stackoverflow. Самый близкий ответ, который я смог найти для своей проблемы, дан здесь: >Как эффективно записывать пиксели на экран с помощью Direct2D, но я не могу понять, как использовать ID2D1RenderTarget::CreateBitmap(). Вероятно, это очень просто, но я новичок в DirectX и не смог найти примеров того, как это сделать. Так что, вероятно, все, что мне нужно, это исчерпывающий пример того, как использовать CreateBitmap и DrawBitmap для создания и рисования растрового изображения из массива.

Моя основная программа в основном основана на этом руководстве: https://www.youtube.com/watch?v=p91FvlnyOyo&list=PLKK11Ligqitij8r6hd6tfqqesh3T_xWJA&index=1

Класс GameEngine управляет различными сценами и обрабатывает их. Каждая сцена наследуется от класса GameScene. Класс GameScene имеет указатель на экземпляр моего класса Graphics, который просто взаимодействует с DirectX и имеет функции быстрого доступа, так что я могу просто вызвать Graphics.DrawCircle(...), например, вместо использования DirectX. Graphics.SetPixels(SomeType array, int width, int height) — это функция, которую я пытаюсь понять.

Вот функция, над которой я пытаюсь работать. В нем есть код из старой версии, который работал с Win32 API, но не с DirectX:

void Graphics::SetPixels(COLORREF * arr, int width, int height)
{

    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);
    // Create the bitmap and draw it on the screen
    HBITMAP map = CreateBitmap(
        width, // width. 512 in my case
        height, // height
        1, // Color Planes, unfortanutelly don't know what is it actually. Let it be 1
        8 * 4, // Size of memory for one pixel in bits (in win32 4 bytes = 4*8 bits)
        (void*)arr); // pointer to array
    // Temp HDC to copy picture
    HDC src = CreateCompatibleDC(hdc); // hdc - Device context for window, I've got earlier with GetDC(hWnd) or GetDC(NULL);
    SelectObject(src, map); // Inserting picture into our temp HDC
    // Copy image from temp HDC to window
    BitBlt(hdc, // Destination
        10,  // x and
        10,  // y - upper-left corner of place, where we'd like to copy
        width, // width of the region
        height, // height
        src, // source
        0,   // x and
        0,   // y of upper left corner  of part of the source, from where we'd like to copy
        SRCCOPY); // Defined DWORD to juct copy pixels. Watch more on msdn;


    DeleteDC(src); // Deleting temp HDC

    EndPaint(hWnd, &ps);

}

Вот функция, которая отображает все

void RaycasterScene1::Render()
{
    GameScene::gfx->BeginDraw(); // This just does renderTarget->BegingDraw()
    int width = 100, height = 100;
    COLORREF * arr = (COLORREF*)calloc(width * height, sizeof(COLORREF));
    for (int i = 0; i < width * height; i++) { arr[i] = RGB(255, 0, 0); }
    GameScene::gfx->SetPixels(arr, width, height);
    GameScene::gfx->EndDraw();
}

Вот мой main.cpp

#include <Windows.h>
#include "GameEngine.h"

Graphics* graphics;

LRESULT CALLBACK WindowProc(...)
{
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_KEYDOWN:
        GameEngine::KeyDown(wParam);
        break;
    case WM_KEYUP:
        GameEngine::KeyUp(wParam);
        break;
    }

    // Otherwse, use the default window behavior
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(...)
{
    // Set up window class
    //...

    // The Graphics class is from my Graphics.h file
    graphics = new Graphics();
    if (!graphics->Init(windowhandle))
    {
        delete graphics;
        return -1;
    }

        // The GameScene class is from one of my files
    GameScene::Init(graphics);

    ShowWindow(windowhandle, nCmdShow);

        // RaycasterScene1 is child class of GameScene
    RaycasterScene1 scene;
        // GameEngine is from one of my files
    GameEngine::SetLevel(&scene);

    MSG message;
    message.message = WM_NULL;

    while (message.message != WM_QUIT)
    {
                // GameEngine::Run() calls RaycasterScene1::Run() which calls RaycasterScene1::Render() which will eventually call Camera::Render() but currently just tries setting up a pixel array to draw with Graphics::SetPixels()
        GameEngine::Run();

        if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
        {
            DispatchMessage(&message);

        }
    }

    return 0;
}

Когда я включаю функции BeginDraw() и EndDraw() в функцию, которая рендерит все, все, что я получаю, это черное окно. Если я уберу их, все, что я получу, это пустое белое окно.

Если проблема не в функции SetPixels, дайте мне знать, хотя я все же хотел бы знать, как реализовать функцию SetPixels с помощью DirectX.


person ElliotThomas    schedule 16.08.2019    source источник
comment
Если вы используете цепочку обмена с вашим окном или цель HWND D2D, не связывайтесь с обычными методами user32, чтобы отрисовать их. Если вы хотите использовать копию памяти для обновления содержимого D2D, вы можете сопоставить поверхность обратного буфера, объекты ID2D1Bitmap также предлагают функции сопоставления памяти.   -  person bunglehead    schedule 16.08.2019