Рейтинговые книги
Читем онлайн Графика для Windows средствами DirectDraw - Стэн Трухильо

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 15 16 17 18 19 20 21 22 23 ... 66

Но перед тем, как переходить к функции BltSurface(), мы закончим рассмотрение функции DrawScene(). Она завершается вызовом функции Flip(). При этом происходит переключение страниц, и подготовленный нами кадр отображается на экране. Функция Flip() получает два аргумента: указатель на поверхность и переменную типа DWORD, предназначенную для установки флагов. Указатель на поверхность необходим лишь в нестандартных ситуациях, когда в переключении поверхностей участвует несколько вторичных буферов. Второй аргумент обычно содержит флаг DDFLIP_WAIT, показывающий, что возврат из функции должен происходить только после того, как переключение страниц завершится.

Функция BltSurface()

Функция BltSurface() класса DirectDrawWin оказывается более гибкой и удобной по сравнению с функциями DirectDrawSurface::Blt() и BltFast(). Мы уже видели, как BltSurface() используется внутри функции BounceWin::DrawScene(), а сейчас рассмотрим саму функцию.

Функция BltSurface() требует передачи четырех аргументов, а пятый аргумент необязателен. Первые два аргумента представляют собой указатели на поверхности — источник и приемник. Следующие два аргумента — координаты x и y, определяющие положение копируемой области на приемнике. По умолчанию блиттинг выполняется без цветовых ключей, однако их можно активизировать с помощью необязательного пятого параметра. Код функции BltSurface() приведен в листинге 3.3.

Листинг 3.3. Функция BltSurface()

BOOL DirectDrawWin::BltSurface(LPDIRECTDRAWSURFACE destsurf, LPDIRECTDRAWSURFACE srcsurf, int x, int y, BOOL srccolorkey) {

 if (destsurf==0 || srcsurf==0) return FALSE;

 BOOL use_fastblt=TRUE;

 DDSURFACEDESC destsurfdesc;

 ZeroMemory(&destsurfdesc, sizeof(destsurfdesc));

 destsurfdesc.dwSize = sizeof(destsurfdesc);

 destsurf->GetSurfaceDesc(&destsurfdesc);

 CRect destrect;

 destrect.left=0;

 destrect.top=0;

 destrect.right=destsurfdesc.dwWidth;

 destrect.bottom=destsurfdesc.dwHeight;

 DDSURFACEDESC srcsurfdesc;

 ZeroMemory(&srcsurfdesc, sizeof(srcsurfdesc));

 srcsurfdesc.dwSize = sizeof(srcsurfdesc);

 srcsurf->GetSurfaceDesc(&srcsurfdesc);

 CRect srcrect;

 srcrect.left=0;

 srcrect.top=0;

 srcrect.right=srcsurfdesc.dwWidth;

 srcrect.bottom=srcsurfdesc.dwHeight;

 // Проверить, нужно ли что-нибудь делать...

 if (x+srcrect.left>=destrect.right) return FALSE;

 if (y+srcrect.top>=destrect.bottom) return FALSE;

 if (x+srcrect.right<=destrect.left) return FALSE;

 if (y+srcrect.bottom<=destrect.top) return FALSE;

 // При необходимости выполнить отсечение

 // для прямоугольной области источника

 if (x+srcrect.right>destrect.right) srcrect.right-=x+srcrect.right-destrect.right;

 if (y+srcrect.bottom>destrect.bottom) srcrect.bottom-=y+srcrect.bottom-destrect.bottom;

 CRect dr;

 if (x<0) {

  srcrect.left=-x;

  x=0;

  dr.left=x;

  dr.top=y;

  dr.right=x+srcrect.Width();

  dr.bottom=y+srcrect.Height();

  use_fastblt=FALSE;

 }

 if (y<0) {

  srcrect.top=-y;

  y=0;

  dr.left=x;

  dr.top=y;

  dr.right=x+srcrect.Width();

  dr.bottom=y+srcrect.Height();

  use_fastblt=FALSE;

 }

 DWORD flags;

 if (use_fastblt) {

  flags=DDBLTFAST_WAIT;

  if (srccolorkey) flags |= DDBLTFAST_SRCCOLORKEY;

  destsurf->BltFast(x, y, srcsurf, &srcrect, flags);

 } else {

  flags=DDBLT_WAIT;

  if (srccolorkey) flags |= DDBLT_KEYSRC;

  destsurf->Blt(&dr, srcsurf, &srcrect, flags, 0);

 }

 return TRUE;

}

Сначала функция BltSurface() проверяет указатели на поверхности. Если хотя бы один из них равен нулю, функция возвращает FALSE, тем самым сообщая о неудаче. Если проверка прошла успешно, два объекта CRect инициализируются в соответствии с размерами поверхностей, полученными с помощью функции DirectDrawSurface::GetSurfaceDesc().

Затем BltSurface() проверяет, что попадает ли точка назначения в границы приемника. Если координаты x и y таковы, что копия не пересекается с поверхностью приемника, блиттинг не нужен, поэтому мы просто выходим из функции.

Если же с точкой назначения все в порядке, функция проверяет, нужно ли выполнять отсечение. Если отсечение не требуется, блит-операция для достижения максимального быстродействия выполняется функцией BltFast(). Если отсечение все же необходимо, возможно, придется пользоваться функцией Blt().

Если отсечение выполняется по правому или нижнему краю источника, функция BltFast() справится с задачей и обрежет выступающую часть копируемой области. Если же отсечение происходит по верхнему или левому краю, приходится работать с функцией Blt(), потому что BltFast() не позволяет задать прямоугольную область приемника. После выполнения блиттинга BltSurface() возвращает TRUE как признак успешного завершения.

Восстановление поверхностей

Наше приложение благополучно инициализируется и выводит графические данные. Теперь необходимо справиться с возможной потерей поверхностей. При рассмотрении функции DirectDrawWin::PreDrawScene мы видели, что DirectDrawWin вызывает виртуальную функцию RestoreSurfaces(), чтобы производный класс получил возможность восстановить потерянные поверхности. Функция RestoreSurfaces() отвечает за восстановление как потерянной памяти поверхности, так и ее содержимого. Функция BounceWin::RestoreSurfaces() выглядит так:

void BounceWin::RestoreSurfaces() {

 if (surf1->IsLost()==FALSE) return;

 CString filename;

 if (GetCurDisplayDepth()==8) filename="tri08.bmp";

 else filename="tri24.bmp";

 surf1->Restore();

 LoadSurface(surf1, filename);

}

DirectDraw может отнимать у неактивного приложения только поверхности, находящиеся в видеопамяти, так что нет смысла в восстановлении поверхностей из системной памяти. Поэтому RestoreSurfaces() сначала проверяет, была ли потеряна единственная вспомогательная поверхность нашего приложения, и если нет — функция прекращает работу. Если же поверхность была потеряна, мы восстанавливаем ее память функцией Restore(), а содержимое — функцией LoadSurface().

Завершение

Как бы ни была хороша программа Bounce, рано или поздно вам захочется убрать ее с экрана. Нажатие клавиши Escape завершает работу программы. Это происходит в обработчике OnKeyDown():

void bounceWin::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {

 if (nChar==VK_ESCAPE) PostMessage(WM_CLOSE);

 DirectDrawWin::OnKeyDown(nChar, nRepCnt, nFlags);

}

Приложение завершает работу, отправляя сообщение WM_CLOSE. В нашем приложении на это сообщение реагирует и класс окна, и класс приложения. Класс окна отвечает сообщением WM_DESTROY, для которого в DirectDrawWin предусмотрен обработчик OnDestroy(). Класс DirectDrawWin в данном обработчике освобождает объекты DirectDraw и всю память, занимаемую приложением. Функция OnDestroy() выглядит так:

void DirectDrawWin::OnDestroy() {

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

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

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

  for (int i=0;i<totaldrivers;i++) {

   if (driver[i].guid) delete[] driver[i].guid;

   free(driver[i].desc);

   free(driver[i].name);

  }

 }

}

Каждый из указателей на интерфейсы DirectDraw сначала освобождается, а затем обнуляется. Затем мы освобождаем память, занятую информацией о драйверах DirectDraw.

Класс приложения обрабатывает завершение в функции ExitInstance(), в которой удаляется класс окна:

int DirectDrawApp::ExitInstance() {

 delete ddwin;

 return CWinApp::ExitInstance();

}

На этом наше знакомство с программой Bounce заканчивается. Однако до сих пор речь шла только о полноэкранных приложениях. Оставшаяся часть этой главы посвящена оконным приложениям.

Оконные приложения

Наверное, вы уже поняли, что полноэкранным приложениям в этой книге уделяется особое внимание. Все программы на CD-ROM работают в полноэкранном режиме, и в этой главе до настоящего момента все внимание было сосредоточено исключительно на полноэкранных приложениях.

Дело в том, что книга посвящена быстродействующим графическим Windows-приложениям, а оконные приложения не обеспечивают оптимального быстродействия. Для полноты картины мы рассмотрим оконные приложения, но не так подробно, как полноэкранные. Впрочем, если вы захотите поддерживать оконный режим в своих приложениях, не все потеряно. Многие описанные приемы, реализованные в полноэкранных приложениях, в равной степени относятся и к оконным.

В начале этой главы мы воспользовались DirectDraw AppWizard и создали приложение Bounce. При этом мы указали, что создаваемая программа должна быть полноэкранной. Чтобы получить рассматриваемый ниже код, следует снова запустить AppWizard и выбрать оконное приложение.

1 ... 15 16 17 18 19 20 21 22 23 ... 66
На этой странице вы можете бесплатно читать книгу Графика для Windows средствами DirectDraw - Стэн Трухильо бесплатно.
Похожие на Графика для Windows средствами DirectDraw - Стэн Трухильо книги

Оставить комментарий