Подскажите, как правильно рисовать прямоугольники разных цветов за одну смену кадров в DirectDraw? Сегодняшняя реальная ценность последнего известна, интересует академическое применение.
Будь то GDI или GDIPlus вопрос решился вызовом в цикле функций/методов FillRect/Graphics::FillRectangle. (Не в курсе, справедливо ли говорит применительно к этим технологиям, что этот весь цикл будет пройден за один кадр).
Прямолинейный подход к вопросу
- Код: Выделить всё
//...
DDrawGraphics *Graphics;
HWND hWnd;
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
//...
while(TRUE)
{
// Check to see if any messages are waiting in the queue
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
}
// If the message is WM_QUIT, exit the while loop
if(msg.message == WM_QUIT)
break;
DoFrame(Graphics);
}
//...
}
//...
void DoFrame(DDrawGraphics *Graphics)
{
DDBLTFX bfx;
memset(&bfx, 0, sizeof(DDBLTFX));
bfx.dwSize = sizeof(DDBLTFX);
RECT rc;
GetClientRect(hWnd, &rc);
int delta = (rc.right - rc.left) / 8;
for(int i = 0; i < 8; ++i)
{
rc.left += i * delta;
rc.right = rc.left + delta;
bfx.dwFillColor = GCP_Colors[i].GetRGB();
Graphics->GetBackBuffer()->Blt(&rc, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bfx);
}
Graphics->Flip(false);
}
Где sColor и GCP_Colors это
- Код: Выделить всё
struct sColor
{
sColor(){sColor(0, 0, 0);};
sColor(BYTE r1, BYTE g1, BYTE b1) : r(r1), g(g1), b(b1){};
BYTE r;
BYTE g;
BYTE b;
COLORREF GetRGB()
{
return RGB(r, g, b);
}
};
sColor GCP_Colors[] = {sColor(255, 255, 255),
sColor(196, 196, 0),
sColor(0, 196, 196),
sColor(0, 196, 0),
sColor(196, 0, 196),
sColor(196, 0, 0),
sColor(0, 0, 196),
sColor(0, 0, 0)
};
Методы класса DDrawGraphics следующие
- Код: Выделить всё
void DDrawGraphics::Flip(bool bNoVSync)
{
if(!m_pddsPrimary)
return;
if(m_bFullscreen)
{
hr = m_pddsPrimary -> Flip(NULL, (bNoVSync) ? DDFLIP_NOVSYNC : DDFLIP_WAIT);
if(FAILED(hr))
MessageBox(NULL, TEXT("[::Flip]: Flip failed"), TEXT("Warning"), MB_OK);
}
else
{
if(!m_pddsBackBuffer || !m_pDD)
return;
if(!bNoVSync)
m_pDD -> WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
hr = m_pddsPrimary -> Blt(&m_rcScreenRect, m_pddsBackBuffer, NULL, DDBLT_WAIT, NULL);
if(FAILED(hr))
MessageBox(NULL, TEXT("[::Flip]: Blt failed"), TEXT("Warning"), MB_OK);
}
}
LPDIRECTDRAWSURFACE7 DDrawGraphics::GetBackBuffer()
{
return m_pddsBackBuffer;
}
Вызов несколько раз подряд Blt не даёт гарантии, что все прямоугольники будут прорисованы, да и не для такого применения проектировался DirectDraw.
Более низкоуровневый подход, получить указатель на поверхность и писать данные прямо туда
- Код: Выделить всё
void DoFrame(DDrawGraphics *Graphics)
{
if(!Graphics)
return;
sSurfDesc desc;
HRESULT hr = Graphics->GetBackBuffer()->Lock(NULL, &desc, DDLOCK_WAIT, NULL);
if(FAILED(hr))
return;
int count = (desc.dwHeight * desc.lPitch)/4;
unsigned int *pBuff = (unsigned int *)desc.lpSurface;
int i = 0;
while(count--)
{
*pBuff++ = GCP_Colors[i].GetRGB();
if(i < 8)
++i;
else
i = 0;
}
hr = Graphics->GetBackBuffer()->Unlock(NULL);
if(FAILED(hr))
return;
Graphics->Flip(false);
Где sSurfDesc
- Код: Выделить всё
template <class T>
struct sAutoZero : public T
{
sAutoZero()
{
memset(this, 0 , sizeof(T));
dwSize = sizeof(T);
}
};
struct sSurfDesc : public sAutoZero<DDSURFACEDESC2>
{
sSurfDesc(int flags = 0, int caps = 0)
{
dwFlags = flags;
ddsCaps.dwCaps = caps;
ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
}
operator LPDDSURFACEDESC2()
{
return this;
}
operator const LPDDSURFACEDESC2() const
{
return(const LPDDSURFACEDESC2)this;
}
};
Но этот подход сопряжён с трудностью получением конкретных координат пикслелей (на то и низко уровневость). Или двигаться в этом направлении? Готовить сцену и давать Flip?
P.S. от 7 апреля 2012г.
Вертикальные прямоугольники можно получить так
- Код: Выделить всё
void DoFrame(DDrawGraphics *Graphics)
{
if(!Graphics)
return;
sSurfDesc desc;
HRESULT hr = Graphics->GetBackBuffer()->Lock(NULL, &desc, DDLOCK_WAIT, NULL);
if(FAILED(hr))
return;
int count = (desc.dwHeight * desc.lPitch)/4;
unsigned int *pBuff = (unsigned int *)desc.lpSurface;
int i = 0, delta = count/8, sm;
sm = delta;
while(count--)
{
*pBuff++ = GCP_Colors[i].GetRGB();
if(sm == 0)
{
sm = delta;
if(i < 8)
++i;
else
i = 0;
}
else
sm--;
}
hr = Graphics->GetBackBuffer()->Unlock(NULL);
if(FAILED(hr))
return;
Graphics->Flip();
}