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

Далее объект отсечения присоединяется к первичной поверхности приложения функцией SetClipper() интерфейса DirectDrawSurface. После такого присоединения можно осуществлять блиттинг на первичную поверхность с помощью функции Blt () интерфейса DirectDrawSurface. Использовать функцию BltFast() нельзя, потому что она не поддерживает отсечения.

Последнее, что происходит в функции CreateFlippingSurface(),  - создание поверхности вторичного буфера. В идеальном варианте нам удастся найти свободную видеопамять в объеме, достаточном для создания внеэкранной поверхности, которая по ширине и высоте совпадает с первичной поверхностью. Я называю такой вариант идеальным из-за преимущества по скорости, характерного для блит-операций в пределах видеопамяти. Кроме того, поскольку вторичный буфер по размерам совпадает с первичной поверхностью, он подойдет для окна любого размера.

Функция CreateFlippingSurfaces() пытается создать «идеальный» вторичный буфер, для чего используются флаг DDSCAPS_VIDEOMEMORY и функция CreateSurface(). Если вызов заканчивается успешно, флаг videobacksurf получает значение TRUE, а функция завершает работу. В противном случае вторичный буфер не создается, а флагу videobacksurf присваивается значение FALSE.

В том варианте вторичный буфер создается приложением в системной памяти позднее, в обработчике OnSize(). Функция OnSize() вызывается при изменении размеров окна приложения. Создавая вторичный буфер по размерам клиентской области окна, мы экономим память. Функция OnSize() выглядит так:

void DirectDrawWin::OnSize(UINT nType, int cx, int cy) {

 CWnd::OnSize(nType, cx, cy);

 CFrameWnd::GetClientRect(&clientrect);

 CFrameWnd::ClientToScreen(&clientrect);

 if (videobacksurf) return;

 DDSURFACEDESC desc;

 ZeroMemory(&desc, sizeof(desc));

 desc.dwSize = sizeof(desc);

 desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;

 desc.dwWidth = clientrect.Width();

 desc.dwHeight = clientrect.Height();

 desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;

 if (backsurf) backsurf->Release(), backsurf=0;

 HRESULT r=ddraw2->CreateSurface(&desc, &backsurf, 0);

 if (r!=DD_OK)  {

  TRACE('failed to create 'backsurf' ');

  return;

 } else TRACE('backsurf w=%d h=%d ', clientrect.Width(), clientrect.Height());

}

Инициализация приложения завершается вызовом функций StorePixelFormatData() и CreateCustomSurfaces(), происходящим в обработчике OnCreate(). Обе функции ведут себя точно так же, как и в полноэкранном приложении.

Графический вывод

Как и в полноэкранном варианте, для обновления экрана класс DirectDrawWin вызывает функцию DrawScene(). Ее реализация для оконных приложений отличается от полноэкранного варианта по двум причинам. Во-первых, поскольку в оконном приложении не выполняется переключение страниц, содержимое вторичного буфера приходится копировать на первичную поверхность. Во-вторых, местонахождение выводимых данных на первичной поверхности должно определяться текущим положением и размерами окна. Помните — первичная поверхность в данном случае изображает весь экран, а не только клиентскую область окна. Оконный вариант DrawScene() выглядит так:

void BounceWin::DrawScene() {

 ClearSurface(backsurf, 0);

 CRect client=GetClientRect();

 int width=client.Width();

 int height=client.Height();

 x+=xinc;

 y+=yinc;

 if (x<-160 || x>width-160) {

  xinc=-xinc;

  x+=xinc;

 }

 if (y<-100 || y>height-100) {

  yinc=-yinc;

  y+=yinc;

 }

 BltSurface(backsurf, surf1, x, y);

 int offsetx=client.left;

 int offsety=client.top;

 RECT srect;

 srect.left=0;

 srect.top=0;

 srect.right=client.Width();

 srect.bottom=client.Height();

 RECT drect;

 drect.left=offsetx;

 drect.top=offsety;

 drect.right=offsetx+client.Width();

 drect.bottom=offsety+client.Height();

 primsurf->Blt(&drect, backsurf, &srect, DDBLT_WAIT, 0);

}

Функция DrawScene() выполняет две блит-операции. Первая копирует содержимое поверхности surf1 на внеэкранную поверхность, которая используется в качестве вторичного буфера. Обратите внимание на применение функции BltSurface(), рассмотренной нами выше. Автоматическое отсечение, выполняемое BltSurface(), позволяет произвольно выбирать позицию на поверхности surf1.

Вторая блит-операция копирует содержимое вторичного буфера на первичную поверхность. На этот раз используется функция Blt(), поскольку к первичной поверхности присоединен объект отсечения. Структуры srect и drect типа RECT определяют области источника и приемника, участвующие в блиттинге. Заметьте, что при вычислении области приемника используются переменные offsetx и offsety, в которых хранятся координаты клиентской области окна. Если убрать эти смещения из структуры drect, программа всегда будет выводить изображение в левом верхнем углу экрана независимо от расположения окна.

Заключение

В этой главе мы изучили почти весь код, сгенерированный AppWizard. Рассмотренное нами базовое приложение нетрудно изменить, поэтому попробуйте немного поэкспериментировать. Например, попытайтесь добавить в программу Bounce дополнительные поверхности или замените вызовы BltSurface() на BltFast() и посмотрите, что получится.

В оставшейся части книги речь в основном пойдет о том, какие изменения следует внести в базовый код, чтобы добиться конкретного результата. В главе 4 мы напишем программу, которая в полной мере использует возможности DirectDraw по переключению видеорежимов.

Глава 4. Видеорежимы и частота смены кадров

В главе 1 я упоминал функции EnumDisplayModes() и SetDisplayMode() интерфейса DirectDraw и говорил о том, что они применяются для обнаружения и активизации видеорежимов. Здесь эти функции будут применены на практике. Сначала мы познакомимся с общими принципами переключения видеорежимов, а затем рассмотрим две демонстрационных программы: Switch и SuperSwitch. Программа

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату