|
|
|||||||||||||||||||||||||||||
|
Использование OpenGL в проектах Delphi for .NETИсточник: delphikingdom Виталий Артемов
Автор: Виталий Артемов, Королевство DelphiВведениеЗанявшись разработкой будущего приложения, программист зачастую сталкивается с дилеммой: использовать ли в своем приложении компоненты стороннего разработчика или создавать собственные? Ответ на этот вопрос неоднозначен, все зависит от конкретной ситуации. Однако неверно утверждать, что применение уже готовых решений всегда предпочтительнее работы "с нуля". Серьезное программное обеспечение отличается детально продуманным интерфейсом, как пользовательским (UI), так и на уровне программного кода. Особенно остро подобный вопрос возникает при организации графического пользовательского интерфейса (GUI), когда необходимо использовать высокопроизводительные средства визуализации и графики. Качественная графика значительно улучшает внешний вид и статус приложения, однако ее применение требует от программиста особых знаний и навыков. Компоненты сторонних разработчиков, к сожалению, нередко оказываются не только бесполезными, но также серьезно препятствуют выполнению работы из-за необходимости освоения и понимания фундаментальных принципов и алгоритмов, на которых они основаны, что в рамках коммерческого проекта вообще чревато фатальными последствиями и недопустимо в принципе. В целом, рекомендовать использование профессиональных графических компонентов можно лишь в том случае, если программист имеет достаточную квалификацию и основательно владеет вопросами, рассмотренными при их создании. Когда речь заходит о написании несложного приложения, в том числе и начинающими программистами, совершенно не обязательно применять объемные и громоздкие компоненты, многие из которых, даже являясь бесплатными, требуют соблюдения каких-то особых условий, например, уведомления об авторстве кода, что, согласитесь, не всегда уместно. На протяжении многих лет OpenGL де-факто считается одним из стандартов в области компьютерной графики. Большое число приложений, заслуживших доверие пользователей по всему миру, реализуют вывод графической информации именно этим программным инструментом. Библиотека OpenGL задумывалась и создавалась достаточно простой в применении и одновременно эффективной, поэтому наряду с более поздними продуктами из той же области она продолжает применяться в новом программном обеспечении. Существует множество компонентов для разработки приложений на основе OpenGL самых различных уровней сложности. Однако следует констатировать факт, что большинство из них написано с использованием таких языков программирования, как C, C#, Java, Visual Basic, Python. Компоненты на основе OpenGL с реализацией под Delphi немногочисленны, особенно в контексте обновленного пакета Delphi for .NET версий 8, 9, 2005, 2006, 2007, 2009 (далее - Delphi .NET). Данная статья нацелена, в первую очередь, на начинающих программистов, использующих Delphi .NET, желающих применять в своих проектах графику OpenGL. К сожалению, данный вопрос весьма сжато освещается в печатных изданиях, не лучше дела обстоят и с сетью Интернет. Вопросы программистов по применению OpenGL в новой среде разработки Delphi после ее перехода на .NET Framework, которые задавались на различных форумах сети, как правило, переадресовывались ответчиками на сайты сторонних разработчиков. Поэтому целью настоящей работы является описание основ применения графической библиотеки OpenGL в проектах Delphi .NET. Рассмотрены полностью работоспособные демонстрационные приложения Win32 с минимальным объемом исходного кода. Тип создаваемого приложенияПоддержка новой технологии .NET Framework большинством современных языков программирования, в том числе Delphi, заставила нас пересмотреть подходы к программированию. Возможно, автор выразит здесь субъективную точку зрения, но библиотека VCL, активно пропагандируемая корпорацией Borland вплоть до 8 й версии Delphi, не совсем оправдала себя. Компоненты этой библиотеки, несмотря на все усилия создателей, не стали стандартом разработки приложений, причем код VCL, по мнению многих квалифицированных экспертов, содержит некоторые неточности. Безусловно, наряду с этим мощная разворачиваемая система .NET Framework несет в себе несравнимо больший потенциал гибкости, эффективности и отлаженности кода. Наверное, именно благодаря этому компании, поддерживающие столь разрозненные ранее объектно-ориентированные языки, приняли идеологию Microsoft по созданию единого системного языка IL, предварительную компиляцию в который можно осуществлять из любого пакета разработки. Как неоднократно говорилось представителями Borland, библиотека VCL .NET была реализована в новых версиях Delphi как удобное средство для перевода проектов со старых версий на проекты .NET. Скорее всего, такой переход, одновременно с освоением новой среды разработки, займет у программистов некоторое время. Базовая структура библиотеки OpenGLРассмотрим структуру OpenGL. Библиотека физически размещается в файле opengl32.dll, который поставляется вместе с операционной системой Microsoft Windows и находится в системной папке C:/WINDOWS/SYSTEM32/opengl32.dll. В этом файле описаны основные типы, процедуры и функции OpenGL, с которыми будет необходимо работать приложению. Помимо этого, в комплекте поставляется компонент OpenGL Utility, размещенный в файле C:/WINDOWS/SYSTEM32/glu32.dll. Это набор утилит (функций) для выполнения типовых задач OpenGL, также используемый в прикладной программе. Программисту рекомендуется просмотреть содержимое системной папки C:/WINDOWS/SYSTEM32 и убедиться в наличии этих двух файлов. В некоторых источниках по OpenGL можно найти ссылку на библиотеку GLUT [3, 5], представляющую собой набор инструментов, для работы, например, с окнами, как основными элементами интерфейса для вывода графики. Однако этот компонент не является стандартным, и его получение возможно через сеть Интернет. В файлах opengl32.dll и glu32.dll описаны функции для обмена информацией между вашим приложением (клиентом) и системой OpenGL (сервером). Приложение формирует набор соответствующих команд, сообщая системе OpenGL, какую графическую информацию необходимо построить и каким способом, а OpenGL через операционную систему взаимодействует с аппаратными средствами компьютера и производит вывод сформированной графической информации. Гибкость библиотеки состоит в том, что в ней нет привязки к платформе компьютера, нет также и описания конкретных графических устройств или их моделей. Библиотека содержит лишь набор командных инструментов, которые программист непосредственно использует в своей программе, и выступает своеобразным "посредником" между приложением, операционной системой и конечным устройством отображения графики. Для корректного взаимодействия с графическим устройством серверу OpenGL требуется информация, по меньшей мере, о двух объектах - ссылке на контекст устройства и формате пикселя. Контекст устройства, Device Context, является структурой, содержащей данные о графических режимах и атрибутах конкретной системы. Эта структура стандартизована, что позволяет через нее установить необходимую для работы OpenGL ссылку на контекст воспроизведения, Rendering Context, которая указывает на средства для отрисовки графической информации. Ссылкой на контекст устройства является величина типа HDC (Handle Device Context), а ссылкой на контекст воспроизведения - HGLRC (Handle OpenGL Rendering Context). Написание следующего параграфа обусловлено одной важной причиной. Переход на Delphi .NET позволил программистам создавать приложения Windows Forms, однако исчезла возможность подключения модулей из предыдущих версий Delphi, например, модуля Windows.pas. Поэтому блоки кода, необходимые для организации работы нашего приложения, нам придется реализовывать заново, максимально используя соглашения среды Delphi .NET. OpenGL в проектах ранних версий DelphiВсе основные функции динамической библиотеки opengl.dll импортируются в соответствующем заголовочном файле OpenGL.pas, расположенном по умолчанию в папке C:/Program Files/Borland/Delphi6/Source/Rtl/Win/OpenGL.pas, если вы используете Delphi 6. Зачастую примеры для Delphi, рекомендуемые многими авторами по OpenGL, начинаются следующим кодом:
В этих примерах предлагается использовать стандартные модули Delphi, а также модуль OpenGL.pas. Мы же пойдем другим путем, и подготовим собственный заголовочный файл с импортированием необходимых функций напрямую из OpenGL. Автор данной статьи все же рекомендует просмотреть файл OpenGL.pas, в целях ознакомления со структурой библиотеки в обычном текстовом формате. Создадим новый проект Windows-приложения с именем MyApplicationOpenGL. Модуль главной формы назовем UnitMainForm.pas, саму главную форму - FormGL (рис. 1). Дополним проект новым модулем GLImports.pas, в котором будут размещены все импортированные из OpenGL функции и типы данных. Библиотека OpenGL оперирует собственными типами данных, точные аналоги которых не всегда находятся в инструментарии того языка, который использует программист. Поэтому важно поставить в четкое соответствие типам OpenGL типы используемого языка, в нашем случае, Delphi. Полный перечень типов данных OpenGL приведен в [1]. Для использования некоторых из них в нашей программе дополним модуль GLImports.pas секцией type:
Обратите внимание, что имена некоторых типов, физически являющихся прототипами стандартных типов Delphi, начинаются с префикса GL. Типы HDC и HGLRC, по сути, являются аналогами стандартного типа THandle из модуля System.pas. Этот модуль автоматически подключается к проекту Delphi, и его явное объявление необязательно. Однако далее мы будем использовать технологию .NET Framework, согласно которой рекомендовано явно указывать пространства имен (модули), в том числе системные. В данном примере код частично заимствован из стандартного модуля Windows.pas. Напомним, что графическая библиотека OpenGL является платформонезависимой, т. е. может воспроизводиться на операционных системах, отличных от Windows. Если детально просмотреть заголовочный файл Windows.pas, часто используемый в проектах Delphi, то можно обнаружить, что в нем также содержатся процедуры и функции, относящиеся к OpenGL, но реализуемые в системе Windows (на это указывает префикс w_):
Характерно, что программисты из Borland внесли эти и другие функции в файл Windows.pas, а не в файл OpenGL.pas. Это объясняется их применимостью только в рамках операционной системы Windows, а их назначение детально описано в [4]: функции wglCreateContext и wglDeleteContext соответственно создают и удаляют контекст воспроизведения OpenGL, а функция wglMakeCurrent устанавливает текущий контекст. Как уже отмечалось, система OpenGL сосредоточена в файлах двух динамически подключаемых библиотек opengl32.dll и glu32.dll, на которые приложение ссылается стандартным соглашением о вызове stdcall. Если вы обнаружите в коде профессионально написанных модулей директивы компилятора {$EXTERNALSYM <имя функции>}, то это следует понимать как организацию взаимодействия с C++Builder, которую мы рассматривать не будем. Наша минимальная программа OpenGL будет воспроизводить на поверхности формы диагональную линию красного цвета. Для этого понадобится еще несколько функций и констант, непосредственно отвечающих за прорисовку линии, которые подробно описаны в [1, 4, 5]:
Операционная система осуществляет низкоуровневые графические операции над элементами управления посредством собственной графической библиотеки GDI, расположенной в файле gdi32.dll. Чтобы организовать взаимодействие приложения с OpenGL, кроме прочего необходимо корректно установить так называемый "формат пикселя". Для этого в наш модуль GLImports.pas ранее был введен тип TPixelFormatDescriptor и соответствующий ему указатель PPixelFormatDescriptor. Теперь понадобятся две функции, описание которых находится все в том же модуле Windows.pas и доступно в справочной системе Delphi, начиная с версии 5:
Окончательно модуль GLImports.pas будет иметь вид:
Вернемся в модуль главной формы приложения UnitMainForm.pas. При создании формы вызывается метод диспетчеризации события, по умолчанию именуемый FormCreate, который мы будем использовать для установки формата пикселя и настройки контекста воспроизведения (используется методика [4]). Метод диспетчеризации события прорисовки формы (по умолчанию FormPaint) будем использовать для отрисовки красной диагональной линии. Наконец, в методе диспетчеризации удаления формы (по умолчанию FormDestroy) освободим занятый контекст воспроизведения. Окончательный код модуля приведен ниже.
Обратите внимание, что из интерфейсной части модуля UnitMainForm.pas удалены практически все ссылки на подключаемые модули (секция uses), созданные IDE Delphi по умолчанию. Это действие носит рекомендательный характер, подчеркивая важность абстрагирования от кода стандартных модулей Delphi. Результат работы приложения показан на следующем рисунке. Рис. 2. Проект Delphi 6 с использованием OpenGL без модулей Windows.pas и OpenGL.pas OpenGL в проектах Delphi .NETВнимательно изучая материалы многочисленных форумов в сети Интернет с момента выхода Delphi 8 до настоящего времени, автор сделал вывод, что взгляды как начинающих программистов, так и экспертов относительно Delphi for .NET значительно поменялись и приняли более "сдержанную" форму. Кстати, большинство программистов, использующих другие языки (не Delphi), переход на платформу .NET восприняли как существенное улучшение в области программирования. Так или иначе, а переход на платформу .NET Framework был неизбежен. К счастью, последние версии среды Delphi for .NET отличаются от "пионерской" Delphi 8 в лучшую сторону. Это связано, очевидно, с приобретением бывшего подразделения корпорации Borland CodeGear сторонней компанией Embarcadero Technologies, занимающейся теперь курированием всего, что связано с Delphi. Результаты не заставили себя ждать - среда RAD 2009 по первым тестам оказалась достаточно стабильной и надежной, хотя и немного ресурсоемкой. Рассмотрим создание простейшего приложения с использованием OpenGL в проекте RAD Studio 2009. Так как нам понадобится пространство имен System.Windows.Forms и другие сборки .NET Framework, укажем тип нашего нового приложения как VCL Forms Application - Delphi for .NET (рис. 3). Рис. 3. Новый проект Delphi for .NET Главная форма приложения создается как VCL-объект, но управляемый средой .NET Framework, как и экземпляры любых объектов-наследников класса System.Object. В частности, экземпляры класса System.Windows.Forms.Form, физически являющиеся обычными Windows-формами, не нуждаются в родителе явно, и могут создаваться конструктором Create без каких-либо параметров. Эту особенность мы применим для создания еще одного окна, на котором непосредственно будет осуществляться отрисовка элементов OpenGL. В данном проекте мы не станем обращаться к библиотекам OpenGL напрямую. Вместо этого будем использовать одну из известных бесплатных библиотек, реализующих функции OpenGL в среде .NET Framework, например, библиотеку Open ToolKit [7]. После сохранения проекта Project1.dpr на жестком диске подключим Open ToolKit, используя стандартную методику Add Reference, указав на жестком диске местоположение файла OpenTK.dll. По умолчанию, если сборка не зарегистрирована в Global Assembly Cache (GAC), она копируется в папку приложения, что в большинстве случаев приемлемо (рис. 4).
Секцию uses модуля главной формы Unit1.pas дополним несколькими пространствами имен:
Убирая из кода комментарии, вставленные средой IDE по умолчанию, добавим далее в секцию глобальных переменных два объекта - форму для вывода графики NetForm и пользовательский элемент управления MyGLControl:
Секция implementation модуля будет содержать лишь два метода диспетчеризации событий - создания формы FormCreate и ее закрытия FormClose. Этот код носит только демонстрационный характер и не может рассматриваться даже как рекомендательный по ряду причин (методы относятся к главной форме Form1, а не к форме NetForm, содержащей полотно OpenGL, форма NetForm не реагирует на изменение размеров и перемещение, отсутствует отдельный метод отрисовки графических примитивов для GLControl и т. п.). Окончательный код модуля приведен ниже.
Форма NetForm создается после главной формы приложения Form1. Затем создается пользовательский элемент управления MyGLControl, который прикрепляется к форме NetForm и занимает всю ее поверхность. Этот элемент является экземпляром специализированного класса OpenTK.GLControl, поэтому все необходимые процедуры по инициализации контекста воспроизведения уже выполнены его создателями внутри самого класса. Конечному пользователю, то есть в данном случае нам, остается установить созданный контекст текущим (метод MyGLControl.MakeCurrent), установить область вывода графики (метод OpenTK.Graphics.GL.Viewport), и, собственно, выполнить рисование красной диагональной линии на черном фоне элемента, используя схему буферизации (методы DrawBuffer, SwapBuffers). Результат выполнения программы приведен на рис. 5. Рис. 5. Применение OpenGL в проекте Delphi for .NET (Open ToolKit) Повторюсь, что данная форма NetForm абсолютно лишена "понятия вежливости" при диалоге с пользователем. Для организации грамотной работы элементов управления, использующих OpenGL, следует обязательно реализовывать их методы по перерисовке, изменению размеров и т. д. В заключение хотелось бы привести некоторую информацию, которую автор считает весьма полезной, особенно для начинающих программистов. В последнем примере мы использовали библиотеку Open ToolKit, но существуют также и другие хорошие инструменты для работы с OpenGL. Вот основные из них:
Удачи и успехов в программировании! Использованная литература
К статье прилагаются файлы: Ссылки по теме
|
|