netlib.narod.ru< Назад | Оглавление | Далее >

Переключение видеорежимов

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

Тем не менее переключение видеорежимов не сводится к простому вызову функции SetDisplayMode(). По этой причине в класс DirectDrawWin была включена функция ActivateDisplayMode(), которая выполняет все необходимые действия для гладкого перехода от одного режима к другому. Вскоре мы рассмотрим ActivateDisplayMode() и все, что она делает, но сначала давайте обратимся к самой функции SetDisplayMode().

Функция SetDisplayMode()

Существуют две версии функции SetDisplayMode(). Первая из них принадлежит интерфейсу DirectDraw и вызывается с тремя аргументами. Вторая версия принадлежит интерфейсу DirectDraw2 и вызывается с пятью аргументами. Прототип первой функции выглядит так:

HRESULT SetDisplayMode(DWORD width, DWORD height, DWORD depth);

СОВЕТ


Для любознательных читателей. Заглянув в заголовочный файл DirectDraw (ddraw.h), вы не найдете в нем этого прототипа. Это объясняется тем, что все функции DirectDraw описываются на IDL (языке определения интерфейсов) спецификации COM. На IDL функция SetDisplayMode() выглядит так:

STDMETHOD(SetDisplayMode)(THIS_ DWORD, DWORD, DWORD) PURE;
Для наших целей IDL не нужен. Все, что нам необходимо знать, — имя функции, тип возвращаемого значения, а также количество и типы аргументов. Все эти сведения более четко описываются традиционными прототипами функций, которые и приводятся в книге и справочных файлах DirectX.


Функция SetDisplayMode(), как и большинство функций DirectX API, возвращает значение типа HRESULT — 32-разрядную величину с описанием результата вызова функции. Ее значение DD_OK показывает, что вызов оказался успешным.

Версия SetDisplayMode() из интерфейса DirectDraw получает три аргумента типа DWORD. Эти аргументы определяют разрешение экрана и глубину пикселей нужного видеорежима, поэтому стандартный видеорежим VGA 640x480x8 активизируется так:

ddraw1->SetDisplayMode(640, 480, 8);

Выглядит довольно просто, поэтому давайте перейдем к версии SetDisplayMode() из интерфейса DirectDraw2. Ее традиционный прототип выглядит так:

HRESULT SetDisplayMode(DWORD width, DWORD height, DWORD depth, 
                       DWORD refreshrate, DWORD flags);

В этой версии появляются два дополнительных аргумента: частота смены кадров и двойное слово, которое может быть использовано в будущих версиях DirectDraw, а пока должно быть равно нулю. В расширенной версии SetDisplayMode() стандартный видеорежим VGA 640x480x8 можно активизировать так:

ddraw1->SetDisplayMode(640, 480, 8, 0, 0);

В данном случае вместо частоты смены кадров передается 0; это означает, что должна быть использована частота, принятая по умолчанию. Кроме того, можно указать конкретное значение частоты (60 Гц в следующем примере):

ddraw1->SetDisplayMode(640, 480, 8, 60, 0);

Однако не следует думать, что вы можете задать любую частоту (или другие параметры видеорежима). Перед тем как вызывать SetDisplayMode(), необходимо сначала определить параметры и частоты допустимых видеорежимов.

Обнаружение видеорежимов и частот смены кадров

В главе 3 говорилось о том, как функция EnumDisplayModes() интерфейса DirectDraw перечисляет все поддерживаемые видеорежимы. Через косвенно вызываемую функцию она сообщает вашему приложению о каждом видеорежиме, поддерживаемом установленными видеоустройствами. Прототип функции EnumDisplayModes() выглядит так:

HRESULT EnumDisplayModes(DWORD flags, LPDDSURFACEDESC desc,
                         LPVOID callbackdata, LPDDENUMMODESCALLBACK callback);

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

ddraw->EnumDisplayModes(0, 0, this, DisplayModeAvailable);

Первый и второй аргументы равны нулю; это означает, что мы не указываем флаги и критерии видеорежимов. Поскольку флаги (первый аргумент) не указаны, каждый обнаруженный видеорежим включается в список один и только один раз. Если бы в первом аргументе был указан флаг DDEDM_REFRESHRATES, каждый видеорежим вошел бы в список столько раз, сколько различных частот смены кадров в нем поддерживается. Такая возможность рассматривается ниже в этой главе при работе с частотами смены кадров в программе SuperSwitch.

Функция ActivateDisplayMode()

Как было сказано в начале главы, смена видеорежима не сводится к вызову функции SetDisplayMode(). Функция SetDisplayMode() активизирует нужный режим, но при этом необходимо уничтожить существующие поверхности и создать их заново. Класс DirectDrawWin решает эту задачу за вас. В него входит функция ActivateDisplayMode(), выполняющая все действия, необходимые для активизации видеорежима и восстановления поверхностей приложения. Для удобства давайте снова посмотрим, как выглядит функция ActivateDisplayMode() (см. листинг 4.1).


Листинг 4.1. Функция DirectDrawWin::ActivateDisplayMode()

BOOL DirectDrawWin::ActivateDisplayMode(int mode)
{
    if ( mode < 0 || mode >= totaldisplaymodes)
        return FALSE;

    DWORD width = displaymode[mode].width;
    DWORD height = displaymode[mode].height;
    DWORD depth = displaymode[mode].depth;

    displayrect.left = 0;
    displayrect.top = 0;
    displayrect.right = width;
    displayrect.bottom = height;
    displaydepth = depth;

    ddraw2->SetDisplayMode(width, height, depth, rate, 0);
    curdisplaymode = mode;

    TRACE("---------------- %dx%dx%d (%dhz) ---------------\n",
               width, height, depth, rate);

    if (CreateFlippingSurfaces() == FALSE)
    {
        FatalError("CreateFlippingSurfaces() failed");
        return FALSE;
    }

    StorePixelFormatData();

    if (CreateCustomSurfaces() == FALSE)
    {
        FatalError("CreateCustomSurfaces() failed");
        return FALSE;
    }

    return TRUE;
}


Функция ActivateDisplayMode() получает один аргумент — индекс в отсортированном списке обнаруженных видеорежимов. Сначала индекс проверяется на правильность. Если он соответствует допустимому элементу массива displaymode, высота, ширина и глубина заданного режима извлекаются из массива и используются для инициализации переменных displayrect и displaydepth. Затем атрибуты видеорежима используются при вызове функции SetDisplayMode(), активизирующей новый видеорежим.

Далее функция CreateFlipingSurfaces() создает первичную поверхность со вторичным буфером, а функция StorePixelFormatData() проверяет, не устарел ли формат пикселей DirectDrawWin (форматы пикселей подробно рассматриваются в главе 5). Наконец, мы вызываем функцию CreateCustomSurfaces(), отвечающую за создание вспомогательных поверхностей приложения.

Итак, функция ActivateDisplayMode() автоматизирует процесс переключения видеорежимов. Сначала она проверяет, будут ли при вызове функции SetDisplayMode() использоваться правильные аргументы, а затем восстанавливает поверхности приложения. Настало время применить ее на практике.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz