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():
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() занимается «уборкой мусора» — она закрывает открытые 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 было описано взаимодействие спрайтов с пользователем. В этой главе мы узнаем, как спрайты взаимодействуют друг с другом.
Проверка столкновений (или проверка соударений) — широкий термин, описывающий алгоритмы для обнаружения столкновений между объектами. Термин относится как к плоским, так и к трехмерным объектам, но в этой книге нас интересуют только плоские объекты.
Проверка столкновений — обширная тема, а решения могут существенно изменяться от приложения к приложению. В этой главе мы кратко рассмотрим