Программирование под ЖК-очки

Ляховецкий В.А.


ОСНОВНОЙ АДРЕС СТАТЬИ
http://www.really.ru/review/programming_for_lcd.html


Обсуждение
http://www.really.overtop.ru/forum/viewtopic.php?t=112

Выражаю огромную благодарность неизвестному мне автору, создавшему ныне исчезнувшую страницу http://www.northstar.nm.ru/comp/vr100.htm.

Основные проблемы при разработке ПО связаны с программной синхронизацией частоты обновления кадров ЭЛТ с частотой срабатывания затворов ЖК очков. Все ПО для предъявления стереокадра можно условно разделить на две большие группы:

а) специальное (разнообразные драйверы), написанное производителями видеоадаптеров для обеспечения работы конкретной модели с использованием ее аппаратных особенностей;

б) универсальное, реализующее общие методы формирования стереокадра.

Основное преимущество специального ПО – надежность и стабильность работы. Основной недостаток специального ПО – плохая документированность возможностей функций пользовательских библиотек. При этом производителями зачастую накладываются произвольные ограничения на использование некоторых форматов стереокадра. Рассмотрим 2 варианта специального ПО, предназначенного для видеокарт ASUS V3800 Deluxe и ASUS V6600 Deluxe.

В SDK для видеоадаптера ASUS V3800 Deluxe входит библиотека AsusVR.dll, предоставляющая сервисные функции для работы со стереограммами. Из этих функций наибольший интерес представляют две.

Функция

VRBitBlt2(int nDestX, int nDestY, HANDLE hLSrc, HANDLE hRSrc, LPRECT lpSrcRect)

используется для вывода на экран стереограммы.

nDestX, nDestY – координаты левого нижнего угла изображения,

HLSrc и hRSrc – хэндлеры, указывающие на изображения левой и правой части стереограммы,

lpSrcRect – указатель на структуру, содержащую информацию о высоте и ширине изображения.

Функция

VREnable(HWND hWnd, DWORD dwWidth, DWORD dwHeight, DWORD dwBitsPerPixel, DWORD dwRefreshRate, DWORD dwStereoMode)

используется на старте приложения для того, чтобы установить формат стереокадра для “окна” с хэндлером hWnd с требуемыми шириной dwWidth и высотой dwHeight, количеством бит цветности на пиксель dwBitsPerPixel, частотой обновления кадров dwRefreshRate и форматом стереокадра dwStereoMode.

Переменная, определяющая формат стереокадра, принимает значение VR_INTERLACEMODE (чередование строк с чересстрочной разверткой) и VR_FLIPINGMODE (постраничный).

Для психофизиологических экспериментов желательно использовать постраничный формат стереокадра. Отметим, что случайно-точечная стереограмма – изображение, которое можно успешно предъявлять и в формате чередования строк. Дело в том, что текстура левой и правой частей стереограммы практически одинакова. Поэтому наблюдатель не испытывает затруднения фузии из-за “паразитной” вертикальной диспаратности.

Разработчиками SDK видеоадаптеров ASUS значение частоты обновления кадров dwRefreshRate ограничено величиной 75 Гц. Это означает, что реальная частота обновления кадров для наблюдателя в ЖК очках составит не более 37 Гц. Однако для предъявления статического изображения для большинства испытуемых такой низкой частоты обновления кадров, по-видимому, достаточно.

Интересно отметить, что мне не удалось корректно вызвать эти функции из-под Delphi (подвисала намертво очередь сообщений). Поэтому программу и примеры пришлось писать на C++ Builder.

Пример перехода в стереорежим и вывода стереограммы с помощью видеоадаптера ASUS V3800 Deluxe.

#define VR_FLIPINGMODE 2 //режим чередования страниц

typedef BOOL (*tVREnable)(HWND hWnd, DWORD dwWidth, DWORD dwHeight, DWORD dwBitsPerPixel, DWORD dwRefreshRate, DWORD dwStereoMode);
typedef BOOL (*tVRBitBlt2)(int nDestX,int nDestY,HANDLE hLSrc,HANDLE hRSrc,LPRECT lpSrcRect);

HINSTANCE hDLL;
HBITMAP BitmapL, BitmapR;
tVREnable VREnable;
tVRBitBlt2 VRBitBlt2;

//инициализация
hDLL = LoadLibrary("AsusVr.dll");
(tVREnable)VREnable = (tVREnable)GetProcAddress(hDLL,"VREnable");
(tVRBitBlt2)VRBitBlt2 = (tVRBitBlt2)GetProcAddress(hDLL,"VRBitBlt2");
//переход в стереорежим, Form1 – главная форма приложения
VREnable(Form1->Handle,800, 600, 32, 75, VR_FLIPINGMODE);
//вывод стереограммы
VRBitBlt2(0, 100, BitmapR, BitmapL, NULL);

В SDK видеоадаптеров ASUS V6600 Deluxe и выше входит библиотека VRnn.dll, где nn – две первые цифры номера серии видеокарты. Из ее функций выделим функцию

SetModeInfo(DWORD dwWidth, DWORD dwHeight, DWORD dwBitsPerPixel, DWORD dwRefreshRate, DWORD dwStereoMode),

которая устанавливает формат стереокадра. Ее отличие от функции VREnable заключается в том, что она позволяет использовать только формат чередования строк (в постраничном формате доступна лишь верхняя половина экрана). Значение параметра dwRefreshRate также, как и для видеоадаптера ASUS V3800, ограничено величиной 75 Гц. Это означает, что в АПК предпочтительно использовать видеоадаптер ASUS V3800 Deluxe, позволяющий использовать постраничный формат стереокадра.

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

Пример перехода в стереорежим и вывода стереограммы с помощью видеоадаптера ASUS V6600 Deluxe.

#define VR_INTERLACEMODE 1

typedef BOOL (*tSetModeInfo)(DWORD dwWidth, DWORD dwHeight, DWORD dwBitsPerPixel, DWORD dwRefreshRate, DWORD dwStereoMode);

tSetModeInfo VRSetModeInfo;

HINSTANCE hDLL;
HDC dcMem, dc;
DWORD dwWidth, dwHeight, dwBitsPerPixel, dwRefreshRate, dwStereoMode;
Int maxX, maxY;
HBITMAP MyBitmap;

//инициализация

HDLL = LoadLibrary("Vr66.dll");
(tSetModeInfo)VRSetModeInfo = (tSetModeInfo)GetProcAddress(hDLL,"SetModeInfo");
dc = GetDC(Form1->Handle); // Form1 – главная форма приложения
dcMem = CreateCompatibleDC(dc);
MyBitmap = CreateCompatibleBitmap(dc, maxX, 2*maxY);
VRGetModeInfo(&dwWidth, &dwHeight, &dwBitsPerPixel, &dwRefreshRate, &dwStereoMode);//определяем текущий режим работы видеокарты
VRSetModeInfo(dwWidth, dwHeight, dwBitsPerPixel, dwRefreshRate, VR_INTERLACEMODE);//переходим в чересстрочный стереорежим

SelectObject(dcMem, MyBitmap);
// Image1 – экземпляр типа Timage, расположенный на Form1
// maxX, maxY – размер стереограммы, maxY умножаем на 2 из-за того, что режим
// вывода – чересстрочный, в нечетных строках MyBitmap строки левой части
//стереограммы, а в четных – правой части.
BitBlt(Image1->Canvas->Handle, 0, 0, maxX, 2*maxY, dcMem, 0, 0, SRCCOPY);

Основное преимущество универсальных программ – возможность их использования для управления ЖК очками различных производителей. Однако применение универсальных программ таит в себе некоторые проблемы. Первоначально большинство ЖК очков было рассчитано на работу в среде DOS, в которой легко получить доступ к аппаратным ресурсам компьютера. В настоящее время широкое распространение получила операционная система Windows, и большинство экспериментаторов предпочитают использовать ПО под Windows. Однако реализация поддержки ЖК очков в Windows гораздо сложнее, чем в DOS.

Во-первых, “легальный” способ управления видеосистемой в Windows – использование функций API (интерфейса прикладного программирования), которые выполняются медленнее, чем при низкоуровневом программировании (в среде DOS) контроллера соответствующего устройства, например, видеоадаптера.

Во-вторых, Windows - многозадачная среда, поэтому в ней гораздо труднее обеспечить стабильность необходимых временных параметров работы программы, в следствие чего возможно нарушение синхронизации. Оно может выражаться либо в полной потере стереоэффекта на некоторое время (постоянно показывается лишь одна часть стереограммы), либо во внезапной смене порядка кадров (левая часть стереограммы предъявляется правому глазу, а правая - левому).

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

DirectX – набор интерфейсов разработчика приложений (API) для создания высокопроизводительных мультимедийных приложений. Визуализация стереограмм происходит с помощью библиотеки DirectDraw - части DirectX, основное назначение которой заключается в предоставлении прямого доступа к видеопамяти. Детальное описание функций DirectDraw приведено в SDK DirectX. Опишем здесь лишь необходимую последовательность вызова функций, обращая внимание на значения некоторых их параметров.

Для инициализации DirectDraw использован следующий фрагмент кода.

DirectDrawCreateEx(NULL, &LPVOID(lpDD), IID_IDirectDraw7, NULL);
lpDD->SetCooperativeLevel(Handle, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
lpDD->SetDisplayMode (dwWidth, dwHeight, dwBitsPerPixel, dwRefreshRate, 0);
ddsd.dwSize = sizeof(ddsd);
ddsd.dwBackBufferCount = 1;
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack);

Здесь lpDD – указатель на объект DirectDraw7, IID_IDirectDraw7 – номер (GUID) интерфейса DirectDraw7, Handleхэндлер главного окна приложения, ddsdописание комплексной поверхности (видеобуфера, содержащего первичную “экранную” поверхность lpDDSPrimary и вторичную “заэкранную” поверхность lpDDSBack).

Допустимые комбинации параметров dwWidth, dwHeight, dwBitsPerPixel, dwRefreshRate зависят от конкретного сочетания драйверов монитора и видеоадаптера.

Для работы с ЖК очками необходимо вызывать функцию SetCooperativeLevel, задающую уровень доступа к видеопамяти, с флагами DDSCL_FULLSCREEN и DDSCL_EXCLUSIVE. Такой формат вызова дает полный доступ к видеопамяти и управлению видеорежимами.

Для вывода на экран стереограммы используется следующая последовательность вызова функций DirectDraw, которая вызывается в цикле обработки сообщений приложения.

LpDDSBack->BltFast(nDestX, nDestY, lpDDS, NULL, DDBLTFAST_WAIT);

lpDDSPrimary->Flip(NULL, DDFLIP_WAIT);

Здесь nDestX, nDestY – координаты левого нижнего угла изображения, lpDDS – хэндлер поверхности, содержащей изображение левой или правой части стереограммы. Функция BltFast копирует часть стереограммы в заэкранную поверхность видеобуфера. Функция Flip меняет местами экранную и заэкранную поверхности видеобуфера. Флаги DDBLTFAST_WAIT и DDFLIP_WAIT необходимы - без их использования функции BltFast и Flip возвращают управление сразу после запуска, а при их указании - только после окончания процесса копирования.

Достоинство этого метода заключается в возможности предъявления стереокадра в режиме разбиения на страницы независимо от видеоадаптера

Недостаток этого метода визуализации стереограмм заключается в том, что до старта приложения невозможно определить, в каком кадре (предъявляемом левому или правому глазу) будет присутствовать левая, а в каком – правая часть стереограммы.



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