После выхода моей первой статьи о программировании 3-хмерной графики в Делфи «OpenGL и Delphi» (MK №19 (190)), мне начали приходить письма с различными вопросами по этой теме и с пожеланиями продолжить рассмотрение основ программирования с использованием OpenGL. Но, как уже отмечалось, это материал не одной статьи. Поэтому в этом цикле будут рассмотрены лишь некоторые аспекты программирования, по которым (судя по письмам) у начинающих программистов OpenGL чаще всего возникают вопросы. И для начала материал о том, как оптимизировать приложение, использующее OpenGL, и сделать его более эффектным.
Вид
Многие программы например, игры работают на полный экран и зачастую устанавливают «свое» разрешение. Это делает выводимую графику более эффектной и позволяет сосредоточить на ней внимание пользователя. Во многих случаях полноэкранные приложения работают быстрее, чем в окне. Предлагаю вам один из способов создания такого приложения. Он заключается в следующем: создается форма (на нее ваше приложение будет выводить графику), у которой BorderStyle=bsNone, FormStyle=StayOnTop, а ClientHeight и ClientWidth соответствуют значениям будущего разрешения экрана по вертикали и горизонтали (например, 480 и 640, 600 и 800 и т.д.) Таким образом, при установке требуемого разрешения форма будет занимать весь экран и находиться поверх всех окон. Собственно для установки разрешения используется функция WinAPI ChangeDisplaySettings. Перед ее вызовом свойства формы Left и Top обнуляются чтобы она расположилась в левом верхнем углу экрана. Пример (обработчик события OnCreate формы):
После завершения работы приложения желательно вернуть прежнее разрешение. Делается это следующим образом.
Такой способ довольно удобен и без глюков работает на разных конфигурациях. Единственное «но» устанавливать можно только стандартные разрешения.
Размер
Следующей немаловажной деталью любого приложения является размер. Одно и то же откомпилированное в разных версиях Делфи приложение имеет разный размер. Так, размер созданного в 3-й версии exe-файла (если просто после запуска Делфи сделать компиляцию пустой формы) около 200 Кб, в то время как 6-я выдаст порядка 400. Это своеобразная плата за удобство и простоту в новых версиях в подключаемые модули добавляются новые полезные процедуры, которые зачастую в приложении, работающем с OpenGL, не используются, а только лишь увеличивают объем exe-файла. Чтобы избежать этого, следует отказаться от использования VCL (Visual Component Library), т.е. всего того программного комплекса, который дает возможность создавать и использовать компоненты, определять их свойства и методы с помощью Инспектора Объектов, а также определять события и реакции на них и т.п. После долгого использования VCL переход на программирование с помощью функций API может показаться довольно сложным. Надеюсь, приведенный далее простой пример, взятый мною из примеров к книге М. Краснова «OpenGL и Делфи» поможет вам освоиться.
Впрочем, если вас не смущают лишние 250 Кб, то и не стоит лишний раз беспокоиться. Пример (для сомневающихся объясняю: создайте console application, уберите оттуда все, вставьте туда это):
Это уже рабочая программа, которая выводит пустую форму с заданными размерами и положением на экране (откомпилированный exe-файл занимает всего лишь 17 Кб и может распространяться, в отличие от C++-Buider’овских экзешников, без каких-либо дополнительных DLL). Не буду особо углубляться в описания работы функций (поверьте, это долго и много), а лишь вкратце опишу принципы работы. Итак, программа сильно отличается по виду, хотя принципы событийно-ориентированного приложения в ней сохранены. Структура обычная для Pascal. Для работы ей нужны всего два модуля Windows и Messages. Состоит из оконной функции WindowProc и основного кода. В оконную функцию передаются поступающие сообщения. Если реакция на них не описана в блоке case, то их обрабатывает функция DefWindowProc. В примере код обработчика сообщения WM_DESTROY содержит строки, завершающие работу приложения. Названия сообщений схожи с названиями VCL-событий (OnCreate WM_Create; OnPaint WM_Paint и пр.) Основной код начинается с определения атрибутов класса окна заданием полей структуры WindowClass (подробнее о них в хелпе Win SDK), в которых, кроме всего прочего, задается название (вернее, адрес) оконной функции. После этого функция RegisterClass регистрирует класс окна в системе, а CreateWindow создает окно (или оконный элемент) с заданием заголовка окна, стиля, положения на экране, размеров и пр. Затем окно отображается (ShowWindow) и перерисовывается (UpdateWindow). И заканчивается основной код циклом обработки сообщений. В нем-то и происходит получение сообщения и передача его в оконную функцию.
Чтобы расширить функциональность этого приложения, надо дополнить его своими обработчиками сообщений (почти так же, как и при работе с VCL). Для многих приложений, использующих OpenGL, требуется только форма, поэтому, отказавшись от VCL, можно уменьшить размер приложения почти в 10 раз. И еще: чтобы сделать окно без заголовка и границ (и поверх всех окон), в функции CreateWindow замените параметр стиля ws_overlappedwindow на комбинацию ws_visible or ws_popup or ws_ex_topmost. Чтобы не было видно курсора мыши (к примеру, в полноэкранных приложениях), допишите в программу строку ShowCursor(False). Также в некоторых случаях при переходе в полноэкранный режим с экрана не убирается Панель Задач (Taskbar) в этом случае следует попробовать ShowWindow со вторым параметром SW_MAXIMIZE.
Скорость
Вы, наверное, замечали, что приложения, использующие стандартный таймер Делфи, могут работать с разной скоростью на разных компьютерах. Казалось бы, задан интервал, к примеру, 50 мс, выводится графика Так почему же у одного приятеля на компе с GeForce4 и Pentium 4 этот интервал резко уменьшается, а у другого (с S3 Trio 1 Мб и Pentium 90) сильно растягивается (может, это БГ тайно проводит опыты со временем? Кое-кто не зря жаловался, что загрузка Win98 кажется ему вечностью :-)). Нет, это просто особенность стандартного таймера: если компьютер не успевает выполнить реакцию на тик таймера, то она становится в т.н. очередь, и поэтому приложение может работать по-разному. Один из способов избежать этого заключается в использовании мультимедийного таймера (из модуля mmsystem). Этот таймер позволяет задавать интервал, разрешение (определяет количество миллисекунд, которое можно отвести на обработку тика, т.н. точность таймера; 0 максимальная), а также процедуру, обрабатывающую тик. Чтобы использовать этот таймер, допишите к списку подключаемых модулей mmsystem. Для запуска таймера в программе используется такая запись:
timer переменная, типа uint, идентификатор таймера.
Интервал 50 мс, точность наивысшая, обработчик процедура Ontimer. Процедура является пользовательской и не должна иметь какого-либо отношения к классу формы:
Итак, операция будет выполняться на каждый тик таймера. При завершении работы приложения следует «убить» таймер (иначе ваша ОС начнет сильно тормозить): TimeKillEvent (timer). Таким образом, мультимедийный таймер позволяет создавать приложения, работающие с одинаковой скоростью на разных компьютерах. На маломощных машинах это достигается путем пропуска нескольких кадров анимации. Например, на моей отнюдь не самой мощной конфигурации в особо тяжелых случаях успевают выводится первый и последний кадр анимации, зато я знаю, что на более мощных компьютерах эта анимация будет выводиться плавнее (т.е. как надо, со всеми кадрами), но за то же время. И поэтому без труда можно устроить «грубую» привязку к музыке и прочие увеселения. Конечно же, это не решение проблемы, но все же дает программисту возможность «прыгнуть» немножко выше возможностей своего компьютера :-).
Количество кадров
Иногда требуется узнать, сколько кадров выводит приложение за секунду, т.н. FPS (Frames Per Second). Вот один из способ, позволяющих это сделать:
Количество выведенных за секунду кадров в переменной fpsRate.
На сегодня это все. Теперь вы сможете улучшить свои программы, сделать их более профессиональными с помощью предложенного программного арсенала средств. В следующей статье уже будет информация непосредственно по OpenGL.
P.S. Что касается материалов по OpenGL в Интернете, рекомендую проверить следующие ссылки:
http://www.opengl.org здесь если и не все, то по крайней мере многое. FAQ’s, хэлпы, новости, документация и много-много другой интересной и полезной информации.
http://www.delphi.vitpc.com сайт «Королевство Делфи». Имеется рубрика М. Краснова по использованию OpenGL и Делфи, а также информация чисто по Делфи.
Также на сайте http://www.torry.ruесть много компонентов и модулей для работы с OpenGL.
Остальные сайты, которые мне встречались, содержат мало информации по данной тематике и не заслуживают особого внимания. Кроме того, советую активно использовать хэлп в Делфи в нем есть ответы практически на все вопросы (просто надо хорошо поискать).