Я бы купил эту книгу
Введение
Я бы купил эту книгу по следующим причинам:
• В ней содержится множество программ-примеров.
• Все программы написаны на C++.
• К книге прилагается библиотека, с которой можно легко экспериментировать.
• Все примеры были разработаны в среде Microsoft Visual C++ 4.0.
• В середине книги имеется красивая цветная вкладка.
• Автор встречался с представителями команды, разработавшей Direct3D.
• К книге прилагается полный комплект разработчика DirectX™ 2 Software Development Kit (SDK).
• Некоторые из представленных здесь идей можно воплотить в играх.
• Некоторые ее примеры не имеют отношения к играм.
• Мне больше не на что тратить деньги.
Я бы не стал покупать эту книгу по следующим причинам:
• В ней нет ни одной программы на ассемблере.
• Она не похожа на научный справочник.
• Книга слишком тонкая, чтобы ее можно было подложить под ножку обеденного стола.
• К ней не прилагаются стереоскопические очки.
• У меня уже есть такая книга.
Что вы узнаете из этой книги
Создавая эту книгу, я хотел показать вам, как написать трехмерное приложение для Microsoft Windows 95. Конечно, я не могу предоставить все примеры программ или описания библиотечных функций, которые обязательно понадобятся вам в будущем. Вместо этого я хочу научить вас самостоятельно решать нужную задачу, пользуясь документацией к DirectX 2 SDK и другими справочными материалами по программированию для Windows. Библиотека классов и примеры программ на прилагаемом диске CD-ROM содержат все, что вам может понадобиться для немедленного написания своего первого трехмерного приложения.
Немного истории
До недавнего времени все были уверены, что земля плоская. Это было очень удобно и для картографов, и для моряков. Первые могли нарисовать точное представление земной поверхности на листке бумаги и при этом не забывали предупредить о том, как опасно приближаться к краю. Вторым легко было разбираться в плоских картах плоского мира. Разумеется, моряки предпочитали держаться подальше от краев, на тот случай, если карта окажется неточной. С развитием вычислительной техники моряки стали переносить карты в память своих компьютеров. Хотя компьютеры времен Христофора Колумба еще не имели экранов высокого разрешения и работали как минимум от двух автомобильных
10 ДУ Введение
Немного истории '•fl 11
ции, встроенным в операционную систему. Все готово для создания приложений Windows, работающих с трехмерными объектами; остается лишь понять, как это делается, чему и посвящена настоящая книга.
Разработка трехмерных приложений
Примеры для этой книги создавались на компьютере Dell OptiPlex GXM 5120 с 32 Мб памяти и операционной системой Microsoft Windows 95. Использовались Microsoft Visual C++ 4.0 и DirectX 2 SDK. Я написал весь свой код на C++, а для компиляции и построения приложений применял библиотеки Microsoft Foundation Classes (MFC). Сочетание C++ с MFC позволило мне быстро создать «скелет» приложения, с которым можно было экспериментировать дальше. Я разработал комплект классов C++, инкапсулирующих функции механизма визуализации и облегчающих работу с ними. В этой книге мы рассмотрим разработанные мной классы, научимся использовать и расширять их для ваших собственных целей.
Если вы умеете программировать на С, но еще не перешли на C++ — вот вам отличный повод сделать это! Мой собственный опыт работы с C++ не так уж велик, и примеры будут понятны любому программисту на С, которому в течение нескольких недель пришлось иметь дело с C++. Если же вы не программируете на С, то советую вам вообще пропустить знакомство с ним и сразу начать с C++.
Я разрабатывал свои приложения и классы C++ с чисто практической точки зрения. Другими словами, я попытался создать средства для решения конкретных задач, а не ряд бесконечных примеров для демонстрации тех или иных возможностей. Вы не найдете в моих примерах классов типа CDog, CLabrador или CAardvark. Это вовсе не означает, что мы пропустим большинство возможностей механизма визуализации — мы используем их в той степени, в какой они нужны нам для создания приложений. *
Если вы не знакомы с концепциями трехмерной графики, будет полезно ознакомиться с превосходными трудами, в которых подробно рассматривается эта тема. В качестве справочника я бы предложил «Computer Graphics Principles and Practice» by Foley, vanDam, Feiner and Hughes (Addison-Wesley, 1991) или, например, «3D Computer Graphics» by Glassner (Lyon & Burford, 1989). Впрочем, чтение этих справочных пособий необязательно — развлечений хватит и без них.*
В комплект DirectX 2 SDK входят интерфейсы прикладных программ Direct3D, Directlnput, DirectSound, Direct3Dsound, DirectDraw и DirectPlay. Мы будем пользоваться интерфейсами Direct3D, DirectDraw и Directlnput, однако обойдемся без DirectSound и DirectPlay. В некоторых приложениях используется звук; если на вашем компьютере установлена звуковая карта, то время от времени вы будете приятно удивлены. Интерфейс Direct3D на самом деле состоит из нескольких уровней, самый верхний из которых носит название «абстрактного режима» (Retained Mode). Под ним находится уровень, называемый «непосредственным режимом» (Immediate Mode), а еще ниже — драйверы устройств. Иногда
• Отечестпеипому читателю можно порекомендовать, например, кпт-у Е. В. Шикипа, А. В. Борсс-коиа ^Компьютерная графика. Динамика, реалистические изображения». М.: Диалог-МИФИ, 1995. — Примеч. перец.
ч «* ••'^^w? ,-,
1 2. W Введение
в тексте книги упоминается «механизм визуализации» (rendering engine). Я использую этот термин, подразумевая библиотеку DirectSD в целом, от уровня абстрактного режима до драйверов, а не только растровый генератор (rasterizer), относящийся к непосредственному режиму.
Стиль программирования
Не беспокойтесь, вы не услышите тирады о правильной расстановке отступов или о положении фигурных скобок; я лишь хочу сделать несколько замечаний, относящихся к примерам программ — это именно примеры, не претендующие на роль прототипа рабочей программы. Во многих случаях я упростил код, отказавшись от обработки ошибок и использовав вместо нее директиву ASSERT для осуществления runtime-проверки в отладочной версии. Подобный метод помогает быстро находить самые «глупые» ошибки и выделять те фрагменты, в которых следует производить более тщательную обработку ошибок. Кроме того, учтите, что runtime-исключения в примерах не обрабатываются вообще. Чаще всего исключения возникают при распределении памяти, а это может происходить при конструировании многих различных объектов C++. Следует заметить, что вызов ASSERT для указателей, созданных оператором new, оказывается бессмысленным, так как реализация new для библиотек MFC самостоятельно возбуждает исключение при нехватке памяти для размещения объекта. Итак, для наших целей можно считать, что оператор new всегда работает успешно.
Для обозначения типа переменных используется простая схема, которая берет начало в так называемой «венгерской нотации», применяемой фирмой Microsoft. Мой собственный вариант выглядит несколько проще. В приведенной ниже таблице перечислены используемые префиксы и соответствующие им типы. Время от времени вам могут встретиться и другие префиксы — в таблице приведены наиболее распространенные.
Префикс
Тип
1
d
Р
Pi
m
int
double
Указатель
Указатель на СОМ-интерфейс
Член класса C++
Если вы относитесь к ветеранам программирования для Windows, то наверняка помните ненавистные указатели NEAR и FAR, которые использовались до перехода на 32-разрядные системы. Во многие структуры данных и прототипы функций Windows входят элементы с префиксом 1р, который означает «длинный (или дальний) указатель» (long pointer). Все указатели в моих программах — это просто указатели, и, соответственно, я пользуюсь только одним префиксом — р. Обычно я храню числа в переменных типа int и избегаю длинных целых типов. Если мне нужно значение с плавающей точкой, я всегда использую тип double. При этом расходы на хранение оказываются несколько выше, чем для float, но зато при вызове математических функций удается избежать приведения типа, генерируемого компилятором.
Стиль программирования ^Щ 13
Как видите, я использую несколько упрощенный подход к типам данных, который хорошо служит мне и помогает упростить программы. Разумеется, вы можете делать все, что захотите. Я не собираюсь приучать вас к своему стилю работы. Мое скромное желание — чтобы вы разобрались в моих программах.
Библиотека SdPlus
Существует несколько методик построений примеров, которые эволюционируют по мере изложения материала в книге. Первый вариант — включать в каждый пример лишь тот код, который необходим для текущего уровня понимания читателя. Затем весь код из одного примера копируется в другой и к нему добавляются новые фрагменты. Мне нравится этот подход, которым я воспользовался в своей книге «Animation Techniques in Win32», поскольку там можно было точно определить, какие познания необходимы для понимания примера в каждый конкретный момент.
Тем не менее в этой книге я решил поступить с примерами иначе — с самого начала представлять читателю практически весь код, а потом детально рассматривать только те фрагменты, которые необходимы для каждого примера. Я выбрал такой подход, поскольку для создания даже самого первого примера требуется достаточно большой объем кода. Хотя ничего лишнего в нем нет, на самом деле вам не обязательно с самого начала знать, как все это работает (кроме того, использование единой кодовой основы во всех примерах сокращает вероятность появления мелких ошибок). Я разработал библиотеку, содержащую общий код для всех моих примеров: библиотеку 3dPlus.
Если вас беспокоит производительность работы приложения с большим объемом кода на C++, позвольте вас заверить, что прослойка C++ на самом деле очень тонка. Во многих случаях устанавливается прямое соответствие между вызовом функции класса C++ и обращением к функции СОМ-интерфейса Direct3D;
если пожелаете, можно обойти прослойку C++ и работать напрямую с интерфейсом Direct3D. На самом деле, по мере развития вашего приложения, вы непременно придете к выводу, что в моей библиотеке реализованы не все необходимые функции. В этом случае можно либо самостоятельно расширить библиотеку, либо непосредственно обращаться к интерфейсу Direct3D.
Интерфейс Direct3D
Система Direct3D построена на основе СОМ — составной объектной модели (Component Object Model), технологии, которая используется фирмой Microsoft при создании операционной системы следующего поколения (кодовое наименование Cairo). Direct3D — одно из первых дополнений Windows, использующее эту технологию, если не считать подсистемы связывания и внедрения объектов (OLE). СОМ-объекты при программировании на C++ играют ту же роль, что и библиотеки динамической компоновки (DLL) при программировании для Windows на языке С. Это не значит, что СОМ-объекты могут использоваться только в приложениях, написанных на C++; скорее речь идет о том, что СОМ-объекты предоставляют хорошую основу для создания системных компонентов. Кроме того, они прекрасно уживаются с программами на C++.
В СОМ- объектах используется таблица указателей на их функции, которая обычно называется v-таблицей (vtable). Аналогичный механизм задействован и в C++ для реализации виртуальных функций класса. Подобно тому, как функции
14 Введение
C++ вызываются из программы на С ценой минимальных дополнительных усилий, можно обращаться к интерфейсам СОМ-объектов из программы на С. Работа с интерфейсами СОМ-объектов из программы на С облегчается тем, что она происходит аналогично работе с функциями классов C++. Фрагмент программы на С, в котором встречается обращение к интерфейсу СОМ-объекта, выглядит следующим образом:
pInterface->lpVtbl->Member(pinterface, argi) ;
А вот как выглядит тот же самый фрагмент в программе на C++:
pInterface->Member(argi) ;
Для определения «срока жизни» СОМ-объектов используются счетчики обращений. Когда на СОМ-объект не остается ни одной ссылки, он сам себя уничтожает. Этот простой механизм заметно облегчает совместное использование СОМ-объектов и освобождает программиста от разнообразных хлопот по управлению данными. Тем не менее это означает, что для правильного использования объектов вы должны представлять себе работу механизма подсчета ссылок.
По сути дела каждый раз, когда СОМ-объект возвращает вам указатель на один из своих интерфейсов, он наращивает значение своего счетчика обращений. Копируя указатель на интерфейс, необходимо нарастить значение счетчика обращений вызовом функции AddRef. После завершения работы с указателем следует вызвать функцию Release данного интерфейса, чтобы уменьшить значение счетчика обращений. На самом деле этим дело не ограничивается, но основная суть именно такова. Приведу фрагмент программы на C++, который получает указатель на интерфейс СОМ-объекта, вызывает функцию интерфейса и затем освобождает его:
pinterface = GetSomeCOMInterface() ;
pInterface->CallMember() ;
p!nterface->Release() ;
Обратите внимание на то, что после вызова Release значением указателя пользоваться уже нельзя, так как объект, на который он ссылается, может оказаться уничтоженным (если вы освободили последнюю или единственную копию объекта). Обычно после вызова Release я присваиваю указателю значение NULL, чтобы облегчить поиск программных ошибок — например, попыток использования недопустимого указателя па интерфейс. Если вы любите макросы (лично я их не люблю), то всегда можете создать макрос RELEASE, который вызывает функцию Release и присваивает указателю значение NULL:
ftdefine RELEASE(p) ((р)->Release(); (p)=NULL;)
Я подумал, что изучение технологии трехмерного программирования — и так непростая задача, поэтому «спрятал» СОМ-интерфейсы DirectSD внутри классов библиотеки 3dPlus, написанных на C++. Если вы привыкнете к библиотечным функциям DirectSD, то можете ничего не знать о лежащих в ее основе СОМ-интерфейсах. Но если вы захотите расширить библиотеку или программировать, не пользуясь библиотечными функциями, вам придется познакомиться с работой СОМ-объектов. Ниже мы рассмотрим многие интерфейсы Direct3D,
Интерфейс DirectSD 'в¦ 15
поэтому к концу книги вы будете хорошо представлять себе их работу, независимо от того, собираетесь ли вы непосредственно использовать их или нет.
Если вы хотите больше узнать о СОМ-объектах, рекомендую прочитать книгу «Inside OLE» (second edition), Kraig Brockschmidt, или многочисленные статьи, входящие в Microsoft Developer Library.
Несколько последних замечаний
Знакомясь с примерами программ в тексте книги, вы обычно сможете отличить обращения к объектам библиотеки 3dPlus от обращении к механизму визуализации по именам объектов. Если имя выглядит как С3с)<имя>, то объект относится к классу C++ и является членом библиотеки 3dPlus. Если вы увидите С<имя>, то ire исключено, что объект также входит в библиотеку 3dPlus (или относится к библиотеке MFC), но более вероятно, что перед вами объект C++, созданный всего для одного примера. Если же вы увидите 1<имя>, то это интерфейс, который так или иначе относится к библиотеке Direct3D. Любой указатель, который начинается с р1<имя>, является указателем на интерфейс Direct3D.
При запуске приложений-примеров вы, вероятно, обратите внимание на то, что многие из них имеют черный фон. В книге для удобства используется белый цвет фона.
Работа с диском CD-ROM
Прилагаемый к книге диск содержит примеры приложений, которые демонстрируют изложенные в книге концепции. Вы можете обращаться к файлам приложений прямо на диске, но я бы посоветовал воспользоваться программой Setup для копирования файлов па жесткий диск, где вы сможете поэкспериментировать с ними, модифицировать и использовать их как основу для создания ваших собственных приложений (для этого потребуется примерно 45 Мб дискового пространства). Запустите Setup.exe и следуйте инструкциям на экране. Все примеры приложений копируются на ваш жесткий диск, в каталог \3D (если только вы не изменили каталог, принятый по умолчанию). На диск переносится структура каталогов с примерами, все необходимые файлы для построения и запуска приложений, выполняемые файлы, а также файлы рабочей области проектов (MDP).
Кроме того, в каталоге \MSDX2SDK на диске CD-ROM находится DirectX 2 SDK, a в каталоге \Tools — некоторые утилиты, которые могут пригодиться при трехмерном программировании. В SDK имеется отдельная программа Setup, которую необходимо запустить, а утилиты из каталога Tools можно скопировать вручную в случае необходимости.
Мелким шрифтом
Мои программы никогда не бывают идеальными, а мои подход к решению проблемы может не совпадать с предложенным вами. Кроме того, несмотря на все мои усилия, текст книги, вероятно, содержит опечатки. Если вы найдете какие-либо ошибки или захотите внести предложения, пожалуйста, сообщите мне. Я не обещаю решить за вас все проблемы, но постараюсь конструктивно ответить на все полученные сообщения.
Мой адрес электронной почты: nigel-t@msn.combusy. Найджел Томпсон, 1996 год.