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

         

Функция GetGUID()


Функция GetGUID() применяется для получения GUID (глобального уникального идентификатора) идентифицирующего создаваемое функцией CreateDeviceFromClipper() устройство. Если вместо вызова функции GetGUID() использовать значение NULL, функция CreateDeviceFromClipper() автоматически выберет устройство с цветовой моделью Ramp. Мы вызываем функцию GetGUID() чтобы иметь возможность выбрать цветовую модель Ramp или RGB. Текст функции GetGUID() приведен в листинге 4.2.

Листинг 4.2. Функция GetGUID()

GUID* RMWin::GetGUID() { static GUID* lpguid; HRESULT r; D3DFINDDEVICESEARCH searchdata; memset(&searchdata, 0, sizeof searchdata); searchdata.dwSize = sizeof searchdata; searchdata.dwFlags = D3DFDS_COLORMODEL; searchdata.dcmColorModel = colormodel; static D3DFINDDEVICERESULT resultdata; memset(&resultdata, 0, sizeof resultdata); resultdata.dwSize = sizeof resultdata; LPDIRECTDRAW ddraw; r = DirectDrawCreate(NULL, &ddraw, NULL); if (r != DD_OK) { TRACE("DirectDrawCreate failed\n"); return NULL; } LPDIRECT3D d3d; r = ddraw->QueryInterface(IID_IDirect3D, (void**)&d3d); if (r != D3DRM_OK) { TRACE("d3drm->QueryInterface failed\n"); ddraw->Release(); return NULL; } r = d3d->FindDevice(&searchdata, &resultdata); if (r == D3D_OK) lpguid = &resultdata.guid; else { TRACE("FindDevice failure\n"); lpguid = NULL; } d3d->Release(); ddraw->Release(); return lpguid; }

Перед тем, как продолжить, посмотрим, почему функция GetGUID() такая сложная. Наша задача — получить GUID для заданного устройства Direct3D. Казалось бы, интерфейс Direct3DRM должен предоставлять функцию, выполняющую эту работу. Возможно, библиотека Direct3D и могла бы быть разработана таким способом, но этого не произошло.

Мы применяем абстрактный режим Direct3D, а абстрактный режим в свою очередь зависит от непосредственного режима, который фактически выполняет визуализацию. Это означает, что устройство Direct3D является конструкцией непосредственного режима, и для поиска требуемого устройства необходимо воспользоваься интерфейсом непосредственного режима. Функции непосредственного режима доступны через COM-интерфейс Direct3D.

Мы можем получить указатель на интерфейс Direct3D создав интерфейс DirectDraw и вызвав его функцию QueryInterface(). Это возможно, поскольку объект DirectDraw начиная с DirectX версии 2 поддерживает интерфейс Direct3D. Если бы мы работали с DirectX версии 1, такой вызов QueryInterface() закончился бы неудачей.

Давайте взглянем на начало функции GetGUID() (листинг 4.2). Первое, что делает функция, — это подготовка двух структур, применяемых для хранения информации об устройстве. Структура searchdata используется для указания запрашиваемой цветовой модели, а в структуре resultdata хранятся результаты поиска. Ниже приведен фрагмент программы, создающий и инициализирующий эти структуры:

D3DFINDDEVICESEARCH searchdata; memset(&searchdata, 0, sizeof searchdata); searchdata.dwSize = sizeof searchdata; searchdata.dwFlags = D3DFDS_COLORMODEL; searchdata.dcmColorModel = colormodel; static D3DFINDDEVICERESULT resultdata; memset(&resultdata, 0, sizeof resultdata); resultdata.dwSize = sizeof resultdata;

Функция memset() обнуляет все поля, после чего полю dwSize присваивается размер структуры.

СОВЕТ Поле dwSize. Требование, чтобы поле структуры содержало размер самой структуры, может показаться довольно глупым, но это сделано, чтобы позволить расширение функциональности без модификации старых программ. Microsoft может увеличить размер структуры в будущей версии Direct3D, а программы, написанные сегодня, будут работать, потому что Direct3D сможет определить, основываясь на значении поля dwSize, какая версия структуры используется.

Полю dwFlags присваивается значение константы D3DFDS_COLORMODEL — это указывает, что единственным критерием поиска является заданная цветовая модель устройства. Полю dcmColorModel присваивается значение переменной colormodel. По умолчанию значение переменной colormodel равно D3DCOLOR_MONO, но оно может быть изменено функцией SetColorModel() (см. выше функцию InitInstance()).

На следующем этапе работы функции GetGUID() создается интерфейс DirectDraw:

LPDIRECTDRAW ddraw; r = DirectDrawCreate(NULL, &ddraw, NULL); if (r != DD_OK) { TRACE("DirectDrawCreate failed\n"); return NULL; }

Функция DirectDrawCreate() применяется для получения указателя на интерфейс DirectDraw. Если вызов функции завершается неудачно, макроопределение TRACE отображает соответствующее сообщение, после чего возвращается NULL.

Как только указатель на интерфейс DirectDraw получен, у объекта запрашивается интерфейс Direct3D:

LPDIRECT3D d3d; r = ddraw->QueryInterface(IID_IDirect3D, (void**)&d3d); if (r != D3DRM_OK) { TRACE("d3drm->QueryInterface failed\n"); ddraw->Release(); return NULL; }

Константа IID_IDirect3D представляет собой GUID интерфейса Direct3D и применяется здесь, чтобы указать функции QueryInterface() какой интерфейс мы ищем. Если функция завершается нормально, переменная d3d указывает на экземпляр интерфейса Direct3D. При возникновении ошибки выводится отладочное сообщение и функция возвращает NULL предварительно освободив интерфейс DirectDraw.

Теперь мы можем выполнить поиск GUID устройства:

r = d3d->FindDevice(&searchdata, &resultdata); if (r == D3D_OK) lpguid = &resultdata.guid; else { TRACE("FindDevice failure\n"); lpguid = NULL; }

Функция FindDevice() интерфейса Direct3D получает в качестве аргументов указатели на две подготовленные ранее структуры. Если функция возвращает D3D_OK, значит GUID найден и переменной lpguid присваивается указатель на него.

Обратите внимание, что структура resultdata и переменная lpguid объявлены как статические. Это сделано потому, что GUID представляет собой 128-разрядное значение. Объявив эти переменные статическими, мы можем возвратить указатель на GUID, а не делать копию его значения.

Перед завершением работы функция GetGUID() освобождает интерфейсы DirectDraw и Direct3D.




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