Программирование графики с использованием Direct3D

       

Функция InitDisplayMode()


Функция InitDisplayMode() использует DirectDraw чтобы определить, какие видеорежимы поддерживаются установленной видеокартой. Эти данные используются для создания списка видеорежимов. Затем этот список будет применяться для определения начального видеорежима. Код функции InitDisplayMode() приведен в листинге 10.3.

Листинг 10.3. Функция InitDisplayMode()

BOOL RMWin::InitDisplayMode() { curdisplaymode = 0;

CDC* dc = GetDC(); DWORD curdisplaydepth = dc->GetDeviceCaps(BITSPIXEL); dc->DeleteDC;

ddraw->EnumDisplayModes(0, 0, 0, DisplayModeAvailable); qsort(displaymode, totaldisplaymodes, sizeof(videomode), CompareModes);

for (int i = 0; i < totaldisplaymodes; i++) { DWORD w, h, d; GetDisplayModeDims(i, w, h, d); if (w == 640 && h == 480 && d == curdisplaydepth) curdisplaymode = i; }

GetDisplayModeDims(curdisplaymode, modewidth, modeheight, modedepth); ddraw->SetDisplayMode(modewidth, modeheight, modedepth); return totaldisplaymodes != 0; }

Сначала функция определяет глубину пикселей текущего видеорежима Windows. Это делается с помощью функции GetDeviceCaps(). Мы используем константу BITSPIXEL чтобы указать, что нас интересует количество бит, необходимое для представления одной точки изображения. Полученное значение сохраняется в переменной curdisplaydepth. Мы используем его позднее при выборе начального видеорежима.

Затем вызывается функция EnumDisplayModes() интерфейса DirectDraw. Последний аргумент функции EnumDisplayModes() — это функция обратного вызова, которую DirectDraw будет вызывать каждый раз при обнаружении поддерживаемого видеорежима. Для регистрации обнаруженных видеорежимов функция InitDisplayMode() использует следующую функцию обратного вызова:

HRESULT WINAPI RMWin::DisplayModeAvailable(LPDDSURFACEDESC desc, LPVOID) { int& count = totaldisplaymodes; if (count == MAXDISPLAYMODES) return DDENUMRET_CANCEL;

displaymode[count].width = desc->dwWidth; displaymode[count].height = desc->dwHeight; displaymode[count].depth = desc->ddpfPixelFormat.dwRGBBitCount;


count++; return DDENUMRET_OK; }

Функция обратного вызова DisplayModeAvailable() получает указатель на структуру DDSURFACEDESC. Эта структура описывает обнаруженный режим. Функция обратного вызова использует ее для инициализации элементов массива displaymode. После того, как элемент будет инициализирован, увеличивается переменная totaldisplaymodes (через псевдоним count). Функция возвращает константу DDENUMRET_OK, чтобы указать, что DirectDraw должен продолжить поиск поддерживаемых видеорежимов. Использование в качестве возвращаемого значения константы DDRNUMRET_CANCEL приведет к прекращению перечисления видеорежимов DirectDraw.



Вернемся к функции InitDisplayMode(). После обнаружения всех поддерживаемых видеорежимов вызывается функция Win32 qsort() чтобы выполнить сортировку полученного массива видеорежимов. Вызов функции выглядит следующим образом:

qsort(displaymode, totaldisplaymodes, sizeof(videomode), CompareModes);

Функции qsort() передаются массив displaymode, общее количество обнаруженных видеорежимов, размер каждого элемента массива displaymode и функция сравнения. Функция сравнения (CompareModes()) — это функция обратного вызова, вызываемая из qsort() для определения правильного порядка следования элементов массива. Текст функции CompareModes() приведен в листинге 10.4.

Листинг 10.4. Функция CompareModes()

int RMWin::CompareModes(const void *arg1, const void *arg2) { videomode* mode1 = (videomode*)arg1; videomode* mode2 = (videomode*)arg2;

DWORD volume1 = mode1->width * mode1->height; DWORD volume2 = mode2->width * mode2->height;

if (volume1 < volume2) return -1; else if (volume1 > volume2) return 1;

if (mode1->depth < mode2->depth) return -1; else if (mode1->depth > mode2->depth) return 1;

return 0; }

Для сравнения двух видеорежимов, передаваемых в параметрах функции CompareModes() используются их размерности. Благодаря этому массив displaymode будет отсортирован по размеру экрана в видеорежимах.



Затем из массива displaymode выбирается начальный видеорежим:

for (int i = 0; i < totaldisplaymodes; i++) { DWORD w, h, d; GetDisplayModeDims(i, w, h, d); if (w == 640 && h == 480 && d == curdisplaydepth) curdisplaymode = i; }

Ищется видеорежим 640x480 (он выбран в качестве начального, поскольку практически любая видеокарта поддерживает режим 640x480). В качестве начальной глубины пикселей используется глубина пикселей текущего видеорежима Windows.

Сразу после выбора видеорежима его параметры извлекаются и используются для изменения текущего видеорежима:

GetDisplayModeDims(curdisplaymode, modewidth, modeheight, modedepth); ddraw->SetDisplayMode(modewidth, modeheight, modedepth);

Функция GetDisplayModeDims() извлекает параметры видеорежима, заданного первым аргументом. Переменные modewidth, modeheight и modedepth принадлежат классу RMWin и используются для хранения параметров текущего видеорежима. Полученные параметры видеорежима передаются в аргументах функции SetDisplayMode() интерфейса DirectDraw. Этот вызов функции осуществляет действительное переключение видеорежима и завершает работу функции InitDisplayMode().




Содержание раздела