C++Builder. Учебный курс
.pdfPen = |
C reatePen(PS _ SO L ID , |
1, RGB (2 5 5 ,0 ,0 ) ) ; |
B ru s h |
= C r e a te S o l i d B r u s h (RGB (0 ,0 ,2 5 5 ) ) ; |
|
S e l e c t O b j e c t ( d c , P e n ) ; |
|
|
S e l e c t O b j e c t ( d c , B r u s h ) ; |
|
|
R e c t a n g l e ( d c , 10, 10, 110, |
1 1 0 ); |
|
D e l e t e O b j e c t ( P e n ) ; |
|
|
D e l e t e O b j e c t ( B r u s h ) ; |
|
}
При работе с этими функциями не используются преимуще ства объектно-ориентированного программирования. В связи с этим работать с функциями значительно сложнее, но, с другой стороны, используя эти функции, можно рисовать в окне другой программы или даже на рабочем столе Windows. Для получения ссылки на рабочий стол необходимо в обработчике события O n C reate записать оператор:
dc = G etD C ( 0 ) ;
В примере этого раздела для вывода используются функции GDI потому, что если для вывода на родном окне C++Builder и предоставляет удобное средство - методы свойства формы C anvas, то для вывода на чужом окне мы этими методами вос пользоваться не можем.
11.1.2. Контекст устройства и контекст воспроизведения
В предыдущем примере вы узнали, что ссылка на контекст
устройства - это величина типа HDC. Для ее получения можно вы
звать функцию GetDC, аргументом которой является ссылка на нужное окно.
Ссылке на контекст |
устройства соответствует свойство |
C a n v a s - > H a n d le формы, |
принтера и некоторых компонентов |
C++Builder. |
|
Каков же все-таки смысл контекста устройства, если он и так связан с однозначно определенным объектом - окном, областью
памяти или принтером, и зачем передавать дополнительно какуюто информацию об однозначно определенном объекте?
Для ответа на эти вопросы обратим внимание на замечатель ное свойство вывода в Windows, состоящее в том, что одними и теми же функциями осуществляется вывод на различные устрой ства. Строки программы
F o r m l - > C a n v a s - > E llip s e (0, |
0, |
100, |
1 0 0 ); |
и |
|
|
|
P r i n t e r - > B e g i n D o c ( ) ; |
|
|
|
P r i n t e r - > C a n v a s - > E l l i p s e (0, |
0, |
100, |
1 0 0 ); |
P r i n t e r - > E n d D o c ( ) ; |
|
|
|
рисуют один и тот же круг как на поверхности формы, так и в рас печатываемом документе. Причем, если мы будем выводить раз ноцветную картинку на монохромный принтер, он справится с этой задачей, передавая цвета оттенками серого.
Даже если мы рисуем только на поле формы, мы имеем дело с различными устройствами - нам неизвестно, какова графическая плата компьютера и каковы характеристики текущей установки настроек экрана. Например, имея в своем распоряжении более 16 млн цветов, приложение не заботится об отображении этой бо гатой палитры на экране, располагающем всего 256 цветами. Такие вопросы приложение перекладывает на плечи операционной сис темы, решающей их посредством использования драйверов уст ройств.
Для того чтобы воспользоваться функциями воспроизведения Windows, приложению необходимо только указать ссылку на кон текст устройства, содержащий средства и характеристики устрой ства вывода.
Справочный файл Win32 Programmer's Reference фирмы Microsoft, поставляемый в составе C++Builder, о контексте устрой ства сообщает следующее: «Контекст устройства является струк турой, которая определяет комплект графических объектов и свя занных с ними атрибутов и графические режимы, влияющие на
вывод. Графический объект включает в себя карандаш для изо бражения линии, кисть для закраски и заполнения, растр для копи рования или прокрутки частей экрана, палитру для определения комплекта доступных цветов, области для отсечения и других опе раций, маршрут для операций рисования».
В OpenGL имеется аналогичное ссылке на контекст устройст ва понятие ссылка на контекст воспроизведения.
Графическая система OpenGL, как и любое другое приложе ние Windows (хоть и размещенное в DLL), также нуждается в ссылке на устройство, на которое будет осуществляться вывод. Это специальная ссылка на контекст воспроизведения - величина типа HGLRC ( H a n d le openG L R e n d e r i n g C o n te x t, ссылка на контекст воспроизведения OpenGL).
Таким образом, контекст устройства Windows содержит ин формацию, относящуюся к графическим компонентам GDI, а кон текст воспроизведения содержит информацию, относящуюся к OpenGL, т.е. играет такую же роль, что и контекст устройства для GDI. В частности, упомянутые контексты являются хранилищами состояния системы, например, хранят информацию о текущем цвете карандаша.
11.1.3. Минимальная программа OpenGL
Рассмотрев основные вопросы функционирования приложе ния и его взаимодействия с операционной системой, мы можем перейти к изучению собственно OpenGL. Рассмотрим пример ми нимальной программы, необходимой для работы приложения, ис пользующего функции OpenGL. Эту программу мы в дальнейшем будем использовать в качестве шаблона для написания других программ.
Пример 11.2
Для подключения библиотеки OpenGL выполните следующие действия:
- Поместите в заголовочном файле модуля две команды пре процессора:
#i n c l u d e < g l \ g l . h >
#i n c l u d e < g l \ g l u . h >
- Объявите в заголовочном файле модуля в секции private
переменную hrc типа HGLRC, т.е.
HGLRC h r c ;
Напомним, что hrc - это ссылка на контекст воспроизведе ния библиотеки OpenGL. Смысл этой величины мы рассмотрели в предыдущем разделе.
- Определите в файле реализации модуля функцию
SetDCPixelFormat:
//==========================================
/ / Формат п и к с е л а
//========================================== void __fastcall S etD C PixelF orm at(H D C hdc)
{
i n t P ix e l F o r m a t; PIXELFORMATDESCRIPTOR p f d = {
eizeof(PIXELFORMATDESCRIPTOR) ,
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, 24,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
32,
0 ,
0 ,
PFD_MAIN_PLANE,
0 ,
0 , 0 };
P ix e lF o r m a t = C h o o s e P ix e lF o r m a t( h d c , & p fd ); S e t P i x e lF o r m a t ( h d c , P ix e lF o r m a t, & p fd );
}
Напомним, ссылка на контекст устройства содержит характе ристики устройства и средства отображения. Проще говоря, полу чив ссылку на контекст устройства, мы берем простой либо цвет ной карандаш или кисть с палитрой в миллионы оттенков.
Сервер OpenGL, прежде чем приступать к работе, также дол жен определиться, на каком оборудовании ему придется работать. Это может быть скромная персоналка, а может бьггь и мощная графическая станция.
Прежде чем получить контекст воспроизведения, сервер OpenGL должен получить детальные характеристики используе мого оборудования. Эти характеристики хранятся в специальной структуре PIXELFORMATDESCRIPTOR (описание формата пиксе ла). Смысл этой структуры - детальное описание графической сис темы, на которой происходит работа. Формат пиксела определяет, например, конфигурацию буфера цвета и вспомогательных буфе ров.
Ниже приводятся некоторые рекомендации по поводу запол нения структуры PIXELFORMATDESCRIPTOR.
Константа PFD_DOUBLEBUFFER включает режим двойной буферизации, когда вывод осуществляется не на экран, а в память, затем содержимое буфера выводится на экран. Это очень полез ный режим: если в любом примере на анимацию убрать режим двойной буферизации и все связанные с этим режимом команды, то при выводе кадра будет заметно мерцание. Во всех последую щих примерах мы будем использовать этот режим.
Константу PFD_GENERIC_ACCELERATED имеет смысл ус танавливать только в случае, если компьютер оснащен графиче ским акселератором.
Таким образом, в функции SetDCPixelFormat полям структуры присваиваются желаемые значения, затем вызовом функции ChoosePixelFormat осуществляется запрос системе, поддерживается ли на данном рабочем месте выбранный формат пиксела, и, наконец, вызовом функции SetPixelFormat уста навливается формат пиксела в контексте устройства. Функция
C h o o s e P i x e l F o r m a t |
возвращает индекс формата пиксела, ко |
|||||
торый |
нам |
нужен |
в |
качестве |
аргумента |
функции |
S e t P i x e l F o r m a t .
Заполнив поля структуры PIXELFORMATDESCRIPTOR, мы определяемся со своими пожеланиями к графической системе, на которой будет происходить работа приложения, OpenGL подбира ет наиболее подходящий к нашим пожеланиям формат и устанав ливает уже его в качестве формата пиксела для последующей ра боты. Наши пожелания корректируются сервером OpenGL приме нительно к реальным характеристикам системы.
- Создайте обработчик события O n C r e a t e формы:
v o id __f a s t c a l l T F o rm l: : F o rm C r e a te (T O b je c t * S en d er)
{
S e tD C P ix e lF o r m a t( C a n v a s - > H a n d le ) ;
h r c = w g lC r e a te C o n te x t( C a n v a s - > H a n d l e ) ;
}
Первая строка - обращение к описанной в этом же модуле пользовательской процедуре, задающей формат пиксела. Во вто рой строке обработчика O n C r e a t e задается величина типа
HGLRC, т.е. создается контекст воспроизведения. Аргументом функции w g l C r e a t e C o n t e x t является ссылка на контекст уст ройства, на который будет осуществляться вывод. В нашем случае устройством вывода будет служить окно формы. Для получения этого контекста OpenGL необходима величина типа HDC. Здесь,
как и во многих |
других примерах, мы используем факт, что |
C a n v a s - > H a n d l e |
и есть ссылка на контекст устройства, связан |
ная с окном формы. |
|
Несколько слов по поводу обозначений функций OpenGL. Функции и процедуры, имеющие отношение только к Windowsверсии OpenGL, обычно имеют приставку w g l, как например w g l C r e a t e C o n t e x t , но могут и не иметь такой приставки, Как например S w a p B u f f e r s . Собственно команды OpenGL имеют
приставки g l или g lu в зависимости от размещения в библиоте ках opengl32.dll и glu32.dll, соответственно.
Итак, контекст воспроизведения создан, и теперь можно осу ществлять вывод командами OpenGL.
- Создайте обработчик события O nP aint формы:
v o id __f a s t c a l l T F o rm l: : F o rm P a in t(T O b ject *Sender)
{
/ / |
У становить |
к о н тек ст |
|
|
|
|
|
|
||
w g lM ak e C u rren t (C anvas-> H andle, h rc ) |
; |
|
|
|||||||
g l C l e a r C o l o r ( 0 . 5 , |
0 . 5 , |
0 .7 5 , |
1 . 0 ) ; |
/ / |
цвет |
фона |
||||
/ / |
О чистка |
буфера |
ц вета |
|
|
|
|
|
||
g l C l e a r (GL_COLOR_BUFFER_BIT) ; |
|
|
|
|
||||||
/ / |
Содержимое |
буфера |
на |
экран |
|
|
|
|||
S w a p B u ffe rs(C a n v a s - > H a n d le ) ; |
|
|
|
|
||||||
w g lM ak e C u rren t (0, |
0 ) ; |
/ / |
освободить |
контекст |
||||||
} |
|
|
|
|
|
|
|
|
|
|
|
Первая строка делает контекст воспроизведения текущим, т.е. |
|||||||||
занимает его |
для |
последующего |
вывода. |
Далее |
функция |
|||||
g lC le a r C o lo r |
определяет цвет фона. Все 4 аргумента имеют |
тип C lcam p f, соответствующий вещественным числам в пределах от нуля до единицы. Первые три параметра задают долю красного, зеленого и синего в результирующем цвете.
Следующую строку будем понимать как очистку экрана и ок рашивание его заданным цветом.
В режиме двойной буферизации (см. функцию SetD CPixelForm at) все рисование осуществляется в задний буфер кадра, он яв ляется текущим на всем процессе воспроизведения. По команде S w a p B u ffers текущее содержимое переднего буфера подменя ется содержимым заднего буфера кадра, но текущим буфером по сле этого все равно остается задний.
При завершении работы программы необходимо освободить контекст воспроизведения.
ния. Для обеспечения этой независимости в ней, в частности, оп ределены собственные типы. Их префикс - "GL", например G L int.
В каждой среде программирования в заголовочных файлах эти типы переопределяются согласно собственным типам среды. Разберем, как это делается в C++Builder.
Заголовочный файл C++Builder g l . h начинается с переопре деления стандартных типов C++, например:
t y p e d e f |
int G L in t; |
t y p e d e f |
unsigned int G L uint; |
t y p e d e f |
float G L f lo a t; |
t y p e d e f |
double G Ldouble; |
Рекомендуется использовать с самого начала знакомства именно типы библиотеки OpenGL, даже если вы наизусть знаете их родные для C++ аналоги. Наверняка вам рано или поздно при дется разбираться в чужих программах или переносить свои про граммы в другую среду программирования или даже в другую операционную систему.
Не все из типов OpenGL удается точно перевести. Например, G Lclam pf - вещественное число в пределах от нуля до единицы - в C++ определен просто как f l o a t . Поэтому обычно в програм мах устанавливают «ручную» проверку на вхождение величины такого типа в требуемый диапазон.
В ряду типов OpenGL особо надо сказать о типе GLboolean:
t y p e d e f unsigned char GLboolean;
Соответственно, определены две константы GL_FALSE=CL GL TRUE=1.
I L L S . Tun TColor и цвет в OpenGL
В этом разделе вам необходимо будет самостоятельно напи сать программу, которая будет окрашивать форму в выбранный цвет с использованием функции OpenGL g lC le a rC o lo r. Здесь на форму необходимо поместить кнопку, при нажатии на которую
появляется стандартный диалог Windows выбора цвета. После вы бора окно окрашивается в выбранный цвет, для чего используются команды OpenGL.
Цвет, возвращаемый диалогом, хранится в свойстве C o lo r
компонента класса T C o lo rD ia lo g . Значение OxOOFFFFFF этого свойства соответствует белому цвету, OxOOFFOOOO - синему,
OxOOOOFFOO - зеленому, OxOOOOOOFF - красному. То есть для выделения красной составляющей цвета необходимо вырезать первый слева байт, второй байт даст долю зеленого, третий - сине го. Максимальное значение байта - 2 55, минимальное - ноль. Цвета же OpenGL располагаются в интервале от нуля до единицы.
В программе введите функцию, определяющую тройку со ставляющих цветов для OpenGL по заданному аргументу типа
T C o lo r:
/ / ==================================================
/ / |
П еревод |
ц в е т а и з T C o lo r в OpenGL |
|
v o id |
__f a s t c a l l |
T F o rm l: : C o lorT oG L (T C olor c, G L f lo a t |
|
&R, |
G L f lo a t |
&G, |
G L f lo a t &B) |
{
R = C% 256/255. ;
G = ( ( c /2 5 6 ) % 2 5 6 )/ 2 5 5 . ; В = ( c / 0 x l 0 0 0 0 ) /2 5 5 . ;
}
Таким образом, из аргумента вырезаются нужные байты и масштабируются в интервал [0 ; 1].
Упражнение
1. Самостоятельно напишите программу, которая будет окр шивать форму в выбранный цвет с использованием функции
OpenGL g l C l e a r C o l o r .