if (finaldata==0) return FALSE;

 DWORD dwWidth = (srcfmt->biWidth+3) & ~3;

 DWORD dwHeight = srcfmt->biHeight;

 DDSURFACEDESC desc;

 ZeroMemory(&desc, sizeof(desc));

 desc.dwSize = sizeof(desc);

 r = avisurf->Lock(0, &desc, DDLOCK_WAIT, 0);

 if (r==DD_OK) {

  BYTE* src = finaldata + dwWidth * (dwHeight-1);

  BYTE* dst = (BYTE *)desc.lpSurface;

  for (DWORD y=0; y<dwHeight; y++) {

   memcpy(dst, src, dwWidth);

   dst += desc.lPitch;

   src -= dwWidth;

  }

  avisurf->Unlock(0);

 }

 return TRUE;

}

После блокировки поверхности функция UpdateAviSurface() в цикле копирует каждую строку пикселей AVI-данных в память поверхности. В формате AVI, как и в формате BMP, изображения хранятся в перевернутом виде, поэтому мы начинаем с последней строки буфера данных и двигаемся к его началу.

Функция RestoreSurfaces() 

Все трудное осталось позади, дальше будет легко. Особенно просто реализуется функция RestoreSurfaces():

void AviPlayWin::RestoreSurfaces() {

 avisurf->Restore();

}

Вспомните — функция RestoreSurfaces() вызывается только при восстановлении потерянных поверхностей, а класс DirectDrawWin автоматически восстанавливает первичную поверхность со вторичным буфером. В программе AviPlay остается лишь восстановить поверхность AVI, а для этого достаточно вызвать функцию Restore() интерфейса DirectDrawSurface.

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

Обработка пользовательского ввода 

В программе AviPlay ввод не играет особой роли. Программа реагирует всего на три клавиши, причем одинаково. Ввод с клавиатуры обрабатывается функцией OnKeyDown():

void AviPlayWin::OnKeyDown(UINT key, UINT nRepCnt, UINT nFlags) {

 switch (key) {

 case VK_ESCAPE:

 case VK_SPACE:

 case VK_RETURN:

  ShowDialog();

  break;

 }

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

}

Все три клавиши вызывают функцию ShowDialog(). Аналогично обрабатывается и ввод от мыши, это происходит в функции OnRButtonDown():

void AviPlayWin::OnRButtonDown(UINT nFlags, CPoint point) {

 ShowDialog();

 DirectDrawWin::OnRButtonDown(nFlags, point);

}

Когда пользователь закрывает диалоговое окно для выбора AVI-файла, функция ShowDialog() посылает сообщение WM_CLOSE, сигнализируя о завершении приложения.

Функция OnDestroy() 

Остается лишь завершить приложение. Функция OnDestroy() занимается «уборкой мусора» — она закрывает открытые AVI-потоки, освобождает декомпрессор и буферы данных AVI:

void AviPlayWin::OnDestroy() {

 DirectDrawWin::OnDestroy();

 if (avistream) AVIStreamRelease(avistream), avistream=0;

 if (decomp)  ICClose(decomp), decomp=0;

 if (srcfmt) delete [] srcfmt, srcfmt=0;

 if (dstfmt) delete [] dstfmt, dstfmt=0;

 if (rawdata) {

  TRACE('delete [] rawdata... ');

  delete [] rawdata, rawdata=0;

 }

 if (finaldata) {

  TRACE('delete [] finaldata... ');

  delete [] finaldata, finaldata=0;

 }

 if (avidialog) delete avidialog, avidialog=0;

 AVIFileExit();

}

Обратите внимание на вызов функции AviFileExit() в конце OnDestroy(). Это завершает работу VFW и освобождает все используемые им ресурсы.

Заключение 

Наше знакомство с воспроизведением видеороликов подходит к концу. Честно говоря, чтобы превратить программу AviPlay в полноценный проигрыватель AVI-файлов, вам придется еще немало потрудиться. Необходимо организовать поддержку звука и хронометраж, не говоря уже о том, что VFW обладает многими странностями и в работе с ним приходится много экспериментировать.

И последнее замечание. По неизвестным мне причинам VFW отказывается работать с AVI-файлами, сжатыми кодеками IR32 и IR42 (возможно, есть и другие, но я заметил эти два). С другой стороны, AVI-файлы, использующие кодеки MS-CRAM и Cinepak, работают нормально.

В главе 9 мы возьмемся за проверку столкновений. Наша цель — написать код, который бы обеспечивал точность проверки на уровне пикселей при максимальной эффективности.

Глава 9. Проверка столкновений               

Спрайты, переключение страниц, палитры, поверхности — это просто замечательно, и в предыдущих главах мы узнали немало полезного. Но поместить спрайты на экран и передвигать их туда-сюда — это еще не все. В большинстве приложений изображения, геометрические фигуры и символы на экране должны взаимодействовать с пользователем и друг с другом. В главе 6 при изучении DirectInput было описано взаимодействие спрайтов с пользователем. В этой главе мы узнаем, как спрайты взаимодействуют друг с другом.

Проверка столкновений (или проверка соударений) — широкий термин, описывающий алгоритмы для обнаружения столкновений между объектами. Термин относится как к плоским, так и к трехмерным объектам, но в этой книге нас интересуют только плоские объекты.

Проверка столкновений — обширная тема, а решения могут существенно изменяться от приложения к приложению. В этой главе мы кратко рассмотрим

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

0

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

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