Я пытаюсь создать 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.