numBLUEbits=(WORD)(hiBLUEbit-loBLUEbit+1);
return TRUE;
}
Структура DDPIXELFORMAT используется в функции GetPixelFormat() для получения масок, показывающих, какие биты в каждом пикселе заняты красной, зеленой и синей цветовыми составляющими. Маски точно описывают формат пикселя, но на практике работать с ними оказывается не очень удобно. Вместо того чтобы просто сохранить полученные маски, мы на основании каждой из них инициализируем два целых числа. Первое число равно позиции младшего бита цветовой составляющей, а второе — количеству бит, необходимых для ее представления. Для поверхностей True color (24- и 32-битных) цветовые составляющие всегда представляются 8 битами, но для поверхностей High color (16-битных) это число изменяется (обычно 5, но иногда 6 для зеленой составляющей).
Класс DirectDrawWin содержит шесть переменных для описания формата пикселей: loREDbit, numREDbits, loGREENbit, numGREENbits, loBLUEbit и numBLUEbits. Они используются некоторыми функциями DirectDrawWin, однако эти переменные объявлены как защищенные (protected), поэтому к ним можно обращаться и из классов, производных от DirectDrawWin. Эти переменные будут рассмотрены в главе 5.
На этом инициализация приложения подходит к концу. Функция ActivateDisplayMode() вызывает еще одну функцию, CreateCustomSurfaces(), которая создает вспомогательные поверхности, но к этому моменту инициализация DirectDraw уже завершена. Функция CreateCustomSurfaces() будет рассмотрена в следующем разделе.
Но сначала давайте подведем итоги. Приложение состоит из двух объектов, BounceWin и BounceApp. Объект BounceApp отвечает за создание объекта BounceWin, а BounceWin в свою очередь инициализирует DirectDraw. Сначала он обнаруживает все имеющиеся драйверы DirectDraw, выбирает один из них и использует его для создания экземпляра интерфейса DirectDraw2. Затем он обнаруживает видеорежимы, поддерживаемые инициализированным драйвером, выбирает один из режимов и активизирует его. Далее создается первичная поверхность с возможностью переключения страниц (и вторичным буфером) и, наконец, анализируется формат пикселей для активизированного видеорежима.
Приложение почти готово к работе, но пока у него нет графических данных. Мы подходим к следующему этапу.
Последняя функция, вызываемая в ActivateDisplayMode() (см. листинг 3.2), — CreateCustomSurfaces(). Эта функция является чисто виртуальной, поэтому классы, производные от DirectDrawWin, должны реализовать ее. Функция CreateCustomSurfaces() создает вспомогательные поверхности, а также инициализирует переменные и структуры данных. В классе BounceWin эта функция выглядит так:
BOOL BounceWin::CreateCustomSurfaces() {
CString filename;
if (GetCurDisplayDepth()==8) filename='tri08.bmp';
else filename='tri24.bmp';
if (surf1) surf1->Release(), surf1=0;
surf1=CreateSurface(filename, TRUE);
if (surf1==0) {
FatalError('failed to load BMP');
return FALSE;
}
return TRUE;
}
В приложении Bounce используется одна вспомогательная поверхность, содержимое которой определяется одним из двух BMP-файлов: 8- или 24- битным. Функция использует 8-битный файл, если текущий видеорежим является 8-битным, и 24-битный файл — в противном случае. В принципе один и тот же BMP-файл можно использовать в обоих сценариях, но это неразумно. Поскольку 8-битные файлы могут состоять лишь из 256 цветов, не стоит использовать их в режимах High и True Color. В свою очередь 24-битные изображения не пользуются палитрами и могут содержать до 16 миллионов цветов. Генерация 256 -цветной палитры для такого изображения становится нетривиальной задачей. Функция CreateCustomSurfaces() определяет глубину пикселей текущего видеорежима с помощью функции DirectDrawWin::GetCurDisplayDepth(). На основании полученного результата выбирается имя BMP-файла.
Затем мы проверяем указатель surf1. Если его значение отлично от нуля, поверхность освобождается, а указатель обнуляется. Это происходит из-за того, что функция CreateCustomSurfaces() может вызываться неоднократно. Функция ActivateDisplayMode () вызывает ее при активизации видеорежима, поэтому приложение, которое за время работы меняет несколько видеорежимов, несколько раз вызовет CreateCustomSurfaces(). Если поверхность создавалась ранее, приведенный код освобождает ее.
Затем мы вызываем функцию CreateSurface(), чтобы создать поверхность и загрузить в нее содержимое BMP-файла. Функция CreateSurface() есть в интерфейсе DirectDrawSurface, но в данном случае используется версия из класса DirectDrawWin. Функция CreateSurface() загружает BMP-файл и создает поверхность, размеры и содержимое которой определяются изображением, хранящимся в заданном BMP-файле. CreateSurface() возвращает указатель на созданную поверхность, если все прошло нормально, и ноль — в противном случае.
Обратите внимание на то, что функция CreateSurface() получает два аргумента. Первый из них представляет собой имя загружаемого BMP-файла. Второй аргумент показывает, нужно ли устанавливать палитру BMP-файла. Для 24-битных BMP-файлов этот аргумент игнорируется.
Наше приложение Bounce является очень простым, поэтому функция CreateCustom Surfaces() делает не так уж много. Реальное приложение может создавать десятки и даже сотни поверхностей. Класс DirectDrawWin содержит несколько служебных функций, которые могут пригодиться при работе с поверхностями, поэтому мы ненадолго отвлечемся от приложения Bounce и рассмотрим эти функции:
LPDIRECTDRAWSURFACE CreateSurface(LPCTSTR filename, BOOL installpalette=FALSE);
LPDIRECTDRAWSURFACE CreateSurface(DWORD w, DWORD h);
BOOL LoadSurface(LPDIRECTDRAWSURFACE surf, LPCTSTR filename);
BOOL ClearSurface(LPDIRECTDRAWSURFACE surf, DWORD clr, RECT* rect=0);
BOOL ClearSurface(LPDIRECTDRAWSURFACE surf, DWORD r, DWORD g, DWORD b, RECT* rect=0);
BOOL GetSurfaceDimensions(LPDIRECTDRAWSURFACE surf, DWORD& w, DWORD& h);
Первая функция нам уже знакома. Функция CreateSurface(), получая имя BMP-файла, создает новую поверхность на основании его содержимого. Кроме того, эта функция может извлекать палитру из 8-битных файлов и назначать ее поверхности. Реализация этой функции подробно рассматривается в главе 5.
Вторая функция — CreateSurface() — создает поверхность заданных размеров. Эта функция полезна в тех случаях, когда вам нужна новая поверхность, содержимое которой не связано с BMP-файлом. Данная версия CreateSurface() реализована так:
LPDIRECTDRAWSURFACE DirectDrawWin::CreateSurface(DWORD w, DWORD h) {
DWORD bytes=w*h*(displaydepth/8);
DDSURFACEDESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
desc.dwWidth = w;
desc.dwHeight = h;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
LPDIRECTDRAWSURFACE surf;
HRESULT r=ddraw2->CreateSurface(&desc, &surf, 0);
if (r==DD_OK) {
TRACE('CreateSurface(%d,%d) created in video memory
', w, h);
return surf;
}
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
r=ddraw2->CreateSurface(&desc, &surf, 0);
if (r==DD_OK) {
TRACE('CreateSurface(%d,%d) allocated in system memory
', w, h);
return surf;
}
TRACE('CreateSurface(%d,%d) failed
', w, h);
return 0;
}
Функция CreateSurface() с помощью структуры DDSURFACEDESC описывает поверхность, размеры которой равны передаваемым параметрам w и h. Поле dwFlags показывает, какие поля структуры будут