прямоугольники разных цветов за одну смену кадров в DirectDr

Работа с 2D и 3D графикой, видео, звуком.

Модератор: Mikle

Admiralisimys
Постоялец
Постоялец
 
Сообщения: 318
Зарегистрирован: 01.06.2009 (Пн) 10:26

прямоугольники разных цветов за одну смену кадров в DirectDr

Сообщение Admiralisimys » 06.04.2012 (Пт) 18:00

Приветствую.
Подскажите, как правильно рисовать прямоугольники разных цветов за одну смену кадров в 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();
}
Последний раз редактировалось Mikle 07.04.2012 (Сб) 17:30, всего редактировалось 1 раз.
Причина: Перенёс вопрос в новую тему, в примерах для новичков ему явно не место.

Вернуться в Мультимедиа

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 34

    TopList