MASM.OpenGL.1.First.Blood — Архив WASM.RU
MASM.OPENGL - Глава 1 x z a z e t
787A617A6574406E61726F642E7275MASM.OPENGL
GLьчатай, открой личико!
В предыдущей части мы занимались теорией, а сегодня пришло время практики. Давайте разбираться.
Скелет нашей первой программы.
Синими рамками обведены процедуры нашей программы, в которых мы будем обращатся к подпрограммам API OpenGL. В принципе больше комментировать здесь нечего. Если вы хорошо поработали над уроками Win32API от Iczelion'a, остальная часть схемы (подпрограммы в черных рамках) не должна вызвать недоумения. Если это не так, то работу над Win32API придется продолжить. Остальным слушателям предлагаю перейти к следующей главе.
Таможня дает "добро"
Давайте посмотрим на подпрограмму "CreateOGLWindow" повнимательнее. Ее название говорит само за себя - мы создаем окно, в котором будут отображаться результаты нашего творчества в построении 3D виртуальной реальности. В следующей таблице расписаны шаги нашей подпрограммы, а также состояние OpenGL после каждого из них.
CreateOGLWindow Состояние OpenGL Создаем окно windows приложения --неактивен-- Запрашиваем ОС Windows контекст устройства нашего окна --неактивен-- Настраиваем контекст устройства нашего окна для работы с ним на OpenGL --неактивен-- Сообщаем OpenGL о подготовленном контексте устройства OpenGL создает контекст рендеринга (изображения), пригодный для работы с нашим окном (контекстом устройства) Выбираем созданный ОpenGL'ем контекст изображения (рендеринга) для построения 3D сцен командами API OpenGL OpenGL готов к работе на выбранном контексте изображения - ожидает от нас команды для исполнения ( путь в 3D мир открыт!) MOV EAX, ECX (или любая другая) OpenGL активен (ждет команды) Cразу договоримся - мы будем смотреть на работу нашей программы с API OpenGL как на общение Клиента (наша программа) с Сервером (OpenGL). Представим на минутку, что мы пытаемся взломать секретный Сервер "OpenGL". Что нужно сделать сначала? Определить по какому сетевому протоколу нам удобнее приконектиться к серверу! Допустим, мы выбрали протокол ABC_32бита. Это хорошо, но настоящие "кулхацкеры" не вламываются на секретные сервера со своего домашнего компьютера! Они вламываются с убитых PСишек (напомню, мы работаем в MASM) деревенских интернет-кафе.
Давайте посмотрим на подпрограмму "CreateOGLWindow" повнимательнее. Ее название говорит само за себя - мы создаем окно, в котором будут отображаться результаты нашего творчества в построении 3D виртуальной реальности. В следующей таблице расписаны шаги нашей подпрограммы, а также состояние OpenGL после каждого из них.
Поддерживается ли на них нужный нам протокол ABC_32бита? Нужно обязательно проверить его наличие перед использованием. Если он не поддерживается, то выбираем другой протокол или отказываемся от идеи взлома. По-моему, пока все логично. На этот раз нам повезло – PCшка поддерживает протокол АВС_16бит (хуже, чем ABC_32бита, но хоть что-то). Мы посылаем команду серверу OpenGL с запросом на соединение по протоколу ABC_16бит и получаем сообщение, что сервер готов к соединению. Дальше дело техники - сделать соединение активным. И всё, сервер ОpenGL ожидает от нас команд для исполнения.
Не бойтесь контекстов устройств (device context) – они не кусаются. Вспомним наше дество: детский сад, строгую воспитательницу и неуемную страсть к рисованию. (на стенах, ватманах, на руках шариковой ручкой, на новеньком БМВ богатого дяди острым гвоздем). Но в детском саду у строгой воспитательницы всегда нужно было спрашивать ее разрешение перед тем, как расписывать что-нибудь – «Марья Ивановна (OC Windows), можно я пририсую усы фломастером на вашей фотографии (в окне моей программы)?». А как иначе? За плохое поведение могут и из детского садика исключить («Ваша программа пыталась выполнить недопустимую операцию и будет закрыта» © WIndows), а там столько красивых игрушек!
Давайте договоримся, что под контекстом устройства (device context) мы будем понимать некий объект на котором нам не терпится что-либо нарисовать. В детском саду такими объектами (контекстами устройства) могли быть: лицо лучшего друга (зубной пастой во время «тихого часа»), стена в туалете, асфальтовая дорожка (цветными мелками – милое дело).
В мире Windows мы будем пользоваться 3-мя такими объектами (контекстами устройств) – монитором, принтером и памятью компьютера. API OpenGL может обрисовывать наши картины не только на мониторе, но и на принтере (есть ограничения) и просто рисовать картинку в памяти компьютера (Off-screen rendering. Кстати, только в этом случае мы можем подправлять изображения OpenGL самостоятельно непосредственно в памяти.) Контекст изображения OpenGL (не путать с контекстом устройства) к Windows не имеет никакого отношения, это “внутренняя кухня” OGL.
Теперь, отягощенные знанием о контекстах устройств Windows и контексте изображения OpenGL, еще раз изучите таблицу «CreateOGLWindow».
Что автор имел в виду под «протоколом», например «ABC_32бита»?. Структуру под симпатичным названием PIXELFORMATDESCRIPTOR.
;
; C
; © MSDN Library
typedef struct tagPIXELFORMATDESCRIPTOR { // pfd
WORD nSize;
WORD nVersion;
DWORD dwFlags;
BYTE iPixelType;
BYTE cColorBits;
BYTE cRedBits;
BYTE cRedShift;
BYTE cGreenBits;
BYTE cGreenShift;
BYTE cBlueBits;
BYTE cBlueShift;
BYTE cAlphaBits;
BYTE cAlphaShift;
BYTE cAccumBits;
BYTE cAccumRedBits;
BYTE cAccumGreenBits;
BYTE cAccumBlueBits;
BYTE cAccumAlphaBits;
BYTE cDepthBits;
BYTE cStencilBits;
BYTE cAuxBuffers;
BYTE iLayerType;
BYTE bReserved;
DWORD dwLayerMask;
DWORD dwVisibleMask;
DWORD dwDamageMask;
} PIXELFORMATDESCRIPTOR;
Я специально сделал фонт помельче, чтобы у вас не возникло желание с ним разбираться прямо сейчас. На данном этапе просто насладитесь количеством разных параметров, которые мы сможем выбирать для работы с OpenGL.
Для чего конкретно нужна эта структура? PIXELFORMATDESCRIPTOR определяет формат пикселей графического изображения, например, сколько цветов оно может отображать (16бит или 32бита - вы неоднократно делали этот выбор, играя в компьютерные игры). Механизм работы со структурой предельно простой. Мы «заказываем» нужный нам формат пикселей с которыми хотели бы работать в 3D. Затем отправляем «заказ» OC Windows. Система подбирает нам наиболее подходящий формат из списка тех, что поддерживаются «железом» на данном компьютере и возвращает его порядковый номер (индекс). Мы сообщаем Windows, что будем работать в предложенном формате, и настраиваем контекст устройства окна под него. Теперь мы уверены, что контекст устройства окна и контекст изображения OpenGL будут работать в одинаковых форматах пикселей, т.е. не будет ситуации, когда OpenGL пытается запихнуть 32бита туда, где могут поместится только 16бит. Логично?
MASM.OpenGL.Chapters – первая кровь
Вот как выглядит подпрограмма CreateOGLWindow.
Код (Text):
<font color="#006600">; ; MASMv7 ; ;------------------------------------------------------- </font>CreateOGLWindow <font color="#0000FF">proc</font> <font color="#006600">;------------------------------------------------------- ; Резервируем место для индекса ; формата пикселей, возращаемого Windows </font><b>LOCAL</b> PixelFormat :<b><font color="#804000">DWORD</font></b> <font color="#006600">; Регистрируем класс нашего окна </font> <b>invoke</b> </code><font color="#0000FF">RegisterClassEx</font><code>, <strong>ADDR</strong> wc <font color="#006600">; Oшибка? - "Ошибка при регистрации окна" ; и выходим </font> <font color="#006600">; Создаем окно win32 приложения ; Для окна с OpenGL необходимы WS_CLIPSIBLINGS и WS_CLIPCHILDREN ! ; Выставляем размеры окна 400 x 400</font> <b>invoke</b> <font color="#0000FF">CreateWindowEx</font>, </code><font color="#990066"><code>NULL</code></font><code>, </code><b>ADDR</b><code> szWinClass, </code><b>ADDR</b><code> szWinName, <font color="#990066">WS_CLIPSIBLINGS</font> </code><font color="#0000FF">or</font><code> <font color="#990066">WS_CLIPCHILDREN</font> \</code> <font color="#0000FF">or</font><code> <font color="#990066">WS_OVERLAPPEDWINDOW</font>, 0, 0, 400, 400, <font color="#990066">NULL</font>, <font color="#990066">NULL</font>, hInstance, <font color="#990066">NULL</font> <font color="#006600">; Oшибка? - "Ошибка при создании окна" ; и выходим </font><font color="#0000FF">mov</font> hWnd, </code><b><font color="#0000FF">eax</font></b><code> <font color="#006600">; Подпрграмма GetDC (входит в Win32API) возвращает ; нам указатель на контекст устройства (КУ) нашего окна ; "Марьиванновна, можно мне порисовать на вашей фотографии?" ; Марьиванновна (с кислым лицом) - "Да на, рисуй. У меня еще есть". </font><b>invoke</b> <font color="#0000FF">GetDC</font>, hWnd <font color="#006600">; Ошибка - "Не могу получить указатель КУ окна" ; и выходим </font><font color="#0000FF">mov</font> hDC, <b><font color="#0000FF">eax</font></b> <font color="#006600">; Подпрграмма ChoosePixelFormat входит в Win32API. ; В структуре pfd :PIXELFORMATDESCRIPTOR ; лежит наш "заказ" на пиксельный формат (ПФ), ; который мы хотели бы использовать в OpenGL. ; Просим Windows подобрать нам подходящий ; ПФ из поддерживаемых железом на выбранном ; контексте устройства - hDC </font><b>invoke</b> <font color="#0000FF">ChoosePixelFormat</font>, hDC, <b>ADDR</b> pfd <font color="#006600">; Ошибка - "Нет подходящего пиксельного формата." ; и выходим </font><font color="#0000FF">mov</font> PixelFormat, <b><font color="#0000FF">eax</font></b> <font color="#006600">; Подпрграмма SetPixelFormat входит в Win32API. ; Настраиваем наш контекст устройства (hDC) на ; работу с подходящим пиксельным форматом, также ; сообщаем некоторую дополнительную информацию ; из нашей структуры pfd :PIXELFORMATDESCRIPTOR ; (windows добавит к выбранному ПФ "тонкие настройки") ; "Cоединение КУ с ОpenGL возможно по протоколу ABC_XXbits" </font><b>invoke</b> <font color="#0000FF">SetPixelFormat</font>, hDC,PixelFormat, <b>ADDR</b> pfd <font color="#006600">; Ошибка - "Установка ПФ не удалась." ; и выходим </font> <font color="#006600">; Подпрграмма wglCreateContext входит в API OpenGL (windows версия). ; Просим OpenGL создать у себя контекст изображения, ; который можно отобразить на контексте устройства нашего ; окна -- формат пикселей у КУ и КИ одинаковый! ; "Подготовить OpenGL для коннекта по протоколу ABC_XXbits" </font><b>invoke</b> <font color="#0000FF">wglCreateContext</font>, hDC <font color="#006600">; Ошибка - "Ошибка в создании контекста изображения." ; и выходим </font><font color="#0000FF">mov</font> hRC, eax <font color="#006600">; Подпрграмма wglMakeCurrent входит в API OpenGL (windows версия). ; Делаем созданный котекст изображения (hRC) активным, ; сообщаем на каком контексте устройства (hDC) мы хотим видеть ; результаты выполнения наших комманд к ОpenGL (сегодня мы рисуем : на мониторе). OpenGL готов к выполнению наших комманд, находится : в режиме ожидания. ; Поздравляю, мы в OpenGLe - 3D открыт! </font><b>invoke</b> <font color="#0000FF">wglMakeCurrent</font>, hDC, hRC <font color="#006600">; Oшибка - "Ошибка активизации КИ." ; и выходим </font> <font color="#006600">; Подпрграмма ShowWindow входит в Win32API. ; Являем OpenGL окно миру </font><b>invoke</b> <font color="#0000FF">ShowWindow</font>, hWnd, <font color="#990066">SW_SHOW</font> <font color="#006600">; Подпрграмма SetForegroundWindow входит в Win32API. ; Да не просто являем, а выпячиваем </font><b>invoke</b> <font color="#0000FF">SetForegroundWindow</font>, hWnd <font color="#006600">; Подпрграмма SetFocus входит в Win32API. ; Да не просто являем и выпячиваем, а насильно ; приковываем к нему всеобщее внимание. </font><b>invoke</b> <font color="#0000FF">SetFocus</font>, hWnd return <font color="#990066">TRUE</font> CreateGLWindow <font color="#0000FF">endp</font></code> </pre> <h2 align="center">Keep your country tidy! (англ.)</h2> <p>Как бы Вам понравилось, если на Вашей жилой площади совершенно чужие люди брали ваши кровные контекстные устройства и создавали разные контексты изображения, работали с ними в свое удовольствие, жутко при этом мусорили и, махнув ручкой на прощанье, убирались восвояси, не прибрав за собой? Вот и ОС Windows будет ужасно расстроена, если мы не приберемся.</p> <p>Напомню, что, создавая наше первое OpenGL приложение, мы на время взяли для рисования контекст устройства окна. Затем по нашей просьбе добрый OpenGL выделил для программы частичку себя – контекст изображения. Настоящие джентльмены, поиграв в чужие игрушки, возвращают их хозяевам.</p> <pre><code> <font color="#006600">; ; MASMv7 ; ;------------------------------------------------------- </font>CloseOGLWindow <b><font color="#0000FF">proc</font></b> <font color="#006600">;-------------------------------------------------------</font> <font color="#006600">; Есть ли в нашем распоряжении контекст изображения OpenGL? </font><b>.IF</b> hRC <font color="#0000FF">!=</font> 0 <font color="#006600">; Подпрограмма wglMakeCurrent входит в API OpenGL (windows версия). ; Сообщаем OpenGL, что больше не хотим активного соединения с его ; сервером. ОpenGL перестает быть активным, все наши комманды ему ; будут проигнорированы, хотя созданный для программы контекст ; изображения все еще зарезервирован.</font> <b>invoke</b> <font color="#0000FF">wglMakeCurrent</font>, <font color="#990066">NULL</font>, <font color="#990066">NULL</font> <font color="#006600"> ; Подпрограмма wglDeleteContext входит в API OpenGL (windows версия). ; Мы сообщаем OpenGL, что выделенный для нас контекст изображения ; нам больше не понадобится. Сервер приводит себя в порядок, а мы идем ; своей дорогой. «И разошлись как в море корабли» </font> <b>invoke</b> <font color="#0000FF">wglDeleteContext</font>, hRC <b>.ENDIF</b> <font color="#006600">; Подпрограмма ReleaseDC входит в Win32API. ; Возвращаем фотографию Марьивановне с глубокой благодарностью </font><b>invoke</b> <font color="#0000FF">ReleaseDC</font>, hWnd, hDC <font color="#006600">; Окно нашей программе больше не нужно</font> <b>invoke</b> <font color="#0000FF">DestroyWindow</font>, hWnd <font color="#006600">; Убираем за собой</font> <b>invoke</b> <font color="#0000FF">UnregisterClass</font>, <b>ADDR</b> szClassName, hInstance <font color="#006600">; Рисуем поразительно реальный 3D образ Клаудии Шифер, в полный рост и ; совершенно голую. </font><b>ret</b> <font color="#006600">; Шутка.</font> KillOGLWindow <b><font color="#0000FF">endp</font></b>PFD_SUPPORT_OPENGL equ 020h
Мы узнали почти все, чтобы закончить этот отрывок из МASM.OpenGL.Chapters. На сладкое осталась структура формата пикселей – pfd.
Код (Text):
;<font color="#006600"> ; MASMv7 ; </font>pfd <b><font color="#0000FF">PIXELFORMATDESCRIPTOR</font></b> { \ <b>sizeof</b> <b><font color="#0000FF">PIXELFORMATDESCRIPTOR</font></b>, 1, <code><font color="#990066">PFD_DRAW_TO_WINDOW</font></code> <font color="#0000FF">or</font> <code><font color="#990066">PFD_SUPPORT_OPENGL</font></code>, <code><font color="#990066">PFD_TYPE_RGBA</font></code>, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}Нули нас пока не интересуют.
Единица это pfd.nVersion – версия структуры (да и такое бывает). nVersion всегда равна единице.
32 – это pfd.cColorBits, определяет кол-во битов на один пиксель (bbp), т.е. количество разнообразных цветов в которые можно этот пиксель покрасить. Я взял 32 (а мог бы 24 или 16, например), что даст мне возможность отобразить 4,294,967,295 цветов.
PFD_TYPE_RGBA (pfd. iPixelType)– сообщает Windows, что цвета пикселей мы будем определять через Red Green Blue компоненты (подробнее в следующих главах)
И последним определяем элемент pdf. dwFlags:
PFD_DRAW_TO_WINDOW сообщает Windows о том, что мы будет рендерить (строить 3D сцены) в окно, а не в память, например.
PFD_SUPPORT_OPENGL – у меня нет информации.В этой главе мы казалось бы ничего не сделали особенного. То, что получилось, Вы увидите, когда после внимательнейшего изучения исходника; сами скомпилируете его, если надо – отловите ошибки, а затем запустите. Напоминаю, СНАЧАЛА изучаете исходник, ПОТОМ компилируете, выдерживаете одни сутки, и в самую последнюю очередь запускаете. Так и только так.
Один мой хороший знакомый добился исключительных результатов за непостижимо короткий срок. Когда я попытался выяснить, в чем секрет и какими пособиями он пользовался, ZYtDHE грустно посмотрел в мою сторону и виновато промямлил «Рассыпался винчестер, а на старом не было компилятора». (!!!) Этот парень создавал программы, отлавливал свои ошибки в течении двух недель, так не разу и не запустив код на исполнение. «All errors are made by mistake» (c) ZYtDHE.
Вы замечали, что первое впечатление от знакомства с чем-то новым - самое сильное? Если именно сейчас в эти первые минуты после прочтения текста вы постараетесь вникнуть в философию OpenGL, с самых азов, с вызова его первой подпрограммы, с инициализации его первой структуры, то остальной более продвинутый материал покажется вам логичным продолжением, вы увидите в хаосе нулей и единиц, байтов и двойных слов, в контекстах изображения удивительную красоту и гармонию. И тогда вы сможете импровизировать, как хороший музыкант на любимом инструменте, а возможности API OpenGL будут ограниченны лишь Вашей фантазией.
Информация к размышлению
Так как исходник без комментариев и обработки возможных ошибок после вызова подпрограмм API (на их месте стоят мои комментарии «и выходим» ,смотри выше по тексту), предлагаю следующий конкурс для любознательных – доработайте исходник. Лучший будет опубликован в следующей главе).
Еще необходимо предупредить читателя о том, что откомпилированный исходник может вообще не запуститься. Если это Ваш случай – остается только порадоваться. Ведь потратив некоторое время на самостоятельный поиск и исправление ошибок вы лучше усвоите материал, и значит потратили время не зря. Вам может понадобится отладчик. К сожалению, у меня сейчас при себе нет его номера телефона, а на email он не отвечает. Поищите его в Интернете. Встретите Сафонову Асю, передавайте привет.
Автор работает в редакторе AsmEditor, который можно скачать отсюда (http://www.avtlab.ru/) Так же скачайте и установите базу подсветки синтаксиса, которую любезно предоставил vkim, разработчик VKDEBUG (входит в пакет MASMv7).
Основные возможности AsmEditor:
- подключение различных компиляторов (Ассемблер, Си и другие);
- настраиваемые схемы подсветки ключевых слов;
- быстрый переход между процедурами, функциями, метками;
- возможность подключения файлов помощи (например, win32.hlp) для вызова контекстной справки по выделенному в редакторе слову;
- работа с исходными кодами в DOS-кодировке без потери символов псевдографики;
- меню и дополнительные кнопки с функциями, назначаемыми пользователем;
- настраиваемые "горячие клавиши"; быстрый переход по номеру строки; "закладки"; сохранение позиции курсора и т.д.
- Не требует инсталляции, не вносит изменений в системные файлы и реестр.
- По умолчанию настроен на пакет MASM32
Также скачайте fraps (www.fraps.com) и испробуйте его на каких-нибудь программах.
Для развлечения, поиграйте с графическими режимами в своем любимом FPS, попереключайтесь с 16 на 32 цветность. Постарайтесь объяснить увиденное.
Просто вопросы на засыпку:
1) Если мы будем работать в режиме off-screen rendering’га (т.е. рисовать изображение в памяти компьютера, а не выводить на экран) сможем ли получить любой «заказанный» формат пикселей для роботы на этом контексте устройства (ограничений то по «железу» на память нет)?
2) Что такое wiggle?
3) Почему в нашей программе необходимо указывать WS_CLIPSIBLINGS и WS_CLIPCHILDREN при вызове CreateWindowEx?
MASM.OpenGL.1.First.Blood
Дата публикации 21 июл 2003