Автор: Пользователь скрыл имя, 02 Ноября 2012 в 14:22, курсовая работа
Эта работа посвящена компьютерной графике, а именно тому, как использовать OpenGL в Delphi. OpenGL - это стандартная библиотека для всех 32-разрядных операционных систем, в том числе и для операционной системы Windows. OpenGL - не отдельная программа, а часть операционной системы
ВВЕДЕНИЕ__________________________________________________2стр.
1. Раздел 1 “Windows-приложения“_____________________5стр.
1.1. Событие, сообщение, ссылка ___________________________5стр.
1.2. Перехват сообщений_________________________________10стр.
2. Раздел 2 “Подключение OpenGL”_____________________17стр.
2.1. Минимальная программа OpenGL_____________________17стр.
2.2. Вывод на компоненты Delphi средствами OpenGL _______27стр.
Вывод_____________________________________________________41стр.
Список литературы ____________________________________42стр.
procedure MesDblClick (var MyMessage TWMMouse); message wm LButtonDblClk;
Замечание
Как правило,
перехватчики сообщений для повышения
надежности работы приложения описываются
в блоке protected
Имя процедуры я задал таким, чтобы не появлялось предупреждение компилятора о том, что я перекрываю соответствующее событие формы. Служебное слово message указывает на то, что процедура будет перехватывать сообщение, мнемонику которого указывают за этим словом. Тип аргумента процедуры-перехватчика индивидуален для каждого сообщения. Имя аргумента произвольно, но, конечно, нельзя брать в качестве имени служебное СЛОВО message. Пожалуй, самым сложным в процессе описания перехвата сообщений является определение типа аргумента процедуры, здесь оперативная помощь оказывается малополезной. В четвертой и пятой версиях Delphi инспектор кода облегчает задачу, но незначительно. Чтобы решить эту задачу для сообщения wm_LButtonDblclk, я просмотрел все вхождения фразы "LButtonDblClk" в файле messages. pas и обнаружил строку, подсказавшую решение:
TWMLButtonDblClk = TWMMouse;
В этом же файле я нашел
описание структуры Twmouse, чем и воспользовался
при кодировании процедуры MesDblclick
для получения координат
Замечание
Перехватчики
сообщений приходится писать в тех случаях,
когда в списке событий нет аналога нужного
нам сообщения, а также тогда, когда важна
скорость работы приложения. Обработка
сообщений происходит быстрее обработки
событий, поэтому именно этим способом
мы будем пользоваться в приложениях,
особенно требовательных к скорости работы
в следующем проекте создан обработчик
сообщения wmPaint - перерисовка окна:
protected
procedure WMPaint(var
Msg: TWMPaint); message WM_PAINT; ...
procedure TForml. WMPaint(var Msg: TWMPaint);
var ps: TPaintStruct;
begin BeginPaint(Handle, ps);
Rectangle (Canvas. Handle, 10, 10, 100, 100);
EndPaint(Handle, ps);
end;
Строки Beginpaint и EndPaint присутствуют для более корректной работы приложения, при их удалении появляется неприятное мерцание при изменении размеров окна Обратите внимание на функцию построения прямоугольника: я воспользовался тем, что свойство canvas. Handle и есть ссылка на контекст устройства, соответствующая окну формы. Точно так же, как перехватчики сообщений предпочтительнее обработчиков событий, использование непосредственно ссылок на окно и ссылок на контекст устройства предпочтительнее использования их аналогов из мира ООП.
Работа с таймером
В этом разделе мы разберем, как использовать таймер, основываясь только на функциях API. Поскольку вы наверняка умеете работать с компонентом класса TTimer, вам легко будет уяснить, как это делается на уровне функций API. Посмотрите простой пример, где с течением времени меняется цвет нарисованного кружочка. Первым делом замечаем, что блок описания констант дополнился описанием идентификатора таймера, в качестве которого можно взять любое целое число.
const
AppName = 'WinPaint';
id_Timer = 100; // идентификатор таймера
Идентифицировать таймер необходимо потому, что у приложения их может быть несколько. Для включения таймера (то, что в привычном антураже соответствует Timerl. Enabled: = True) вызывается функция API SetTimer, где задается требуемый интервал таймера:
SetTimer (Window, id_Timer, 200, nil); // установка таймера
Сделал я это перед входом в цикл обработки сообщений, но можно и при обработке сообщения WM_CREATE. Кстати, самое время сказать, что это сообщение обрабатывается в обход цикла обработки сообщений, поэтому таймер, включенный в обработчике WM_CREATE, начнет работать раньше. Оконная функция дополнилась обработкой сообщения, соответствующего такту таймера:
wm_Timer: InvalidateRect (Window, nil, False);
Как видим, работать с таймером, используя только функции API, совсем не сложно. Компонент Delphi TTimer основывается на функциях и сообщениях, которые мы только что рассмотрели.
Работа с мышью и клавиатурой
При нажатой левой кнопки мыши за
указателем остается след. Оконная
функция дополнилась
Down: = not Down;
wm_Create: Down: = False;
wm_LButtonDown, wm_LButtonUp
wm_MouseMove:
begin If Down then begin xpos: = LoWord ( LParam);
ypos: = HiWord ( LParam); InvalidateRect(Window, nil, False); end; end;
wm_Paint: begin If Down then begin dc: = BeginPaint (Window, MyPaint);
Ellipse (dc, xPos, yPos, xPos + 2, yPos + 2);
EndPaint (Window, MyPaint); ReleaseDC (Window, dc);
end;
end;
Последнее,
что мы рассмотрим в данном разделе и что
обязательно потребуется в дальнейшем
- это обработка клавиатуры. Оконная функция
дополнилась обработчиком соответствующего
сообщения
wm_Char: // анализ нажатой клавиши
case wParam of $58, $78: If HiWord {GetKeyState (vk_Shift)) = 0 { Shift }
then
MessageBox(Window, 'X', 'Нажата клавиша', MB_OK) else
MessageBox(Window, 'X вместе с Shift', 'Нажата клавиша', MB_OK);
end; // wm char
При нажатии клавиши 'X'
выводится сообщение, в котором
указано, нажата ли одновременно клавиша
<Shift>. Я использовал
DLL
Файлы DLL (Dynamic Link Library, библиотека динамической компоновки) являются основой программной архитектуры Windows и отличаются от исполняемых файлов фактически только заголовком
Для загрузки операционной системы необходимо запустить файл win com, имеющий размер всего 25 Кбайт. Как легко догадаться, в файл такого размера невозможно поместить код, реализующий всю ту гигантскую работу, которая производится по ходу выполнения любого приложения. Этот файл является загрузчиком ядра операционной системы, физически размещенным в нескольких DLL-файлах. Помимо кода, DLL-файлы могут хранить данные и ресурсы. Например, при изменении значка (ярлыка) пользователю предлагается на выбор набор значков из файла SHELL32. DLL. Библиотека OpenGL физически также размещена в виде двух DLL-файлов: opengl23. dll и glu32. dll. Первый из этих файлов и есть собственно библиотека OpenGL. Назначение его - осуществление взаимодействия с акселератором или программная эмуляция ускорителя за счет центрального процессора. Поддержка ЗD-акселерации осуществляется с помощью полного (устанавливаемого) клиентского драйвера (Installable Client Driver, ICD) и мини-драйвера (Mini-Client Driver, MCD). Библиотека OpenGL реализована по клиент-серверной схеме, т.e. ее одновременно может использовать несколько приложений при единственной копии сервера в памяти или вообще при удаленном расположении сервера (сервер в принципе может располагаться и не на компьютере клиента). Чаще всего DLL представляет собой набор функций и процедур. Как говорится в справке Delphi по DLL, "динамические библиотеки являются идеалом для многоязыковых проектов". Это действительно так: при использовании OpenGL совершенно безразлично, в какой среде созданы сама библиотека и вызывающие ее модули.
Раздел 2 “Подключение OpenGL”
2.1. Минимальная программа OpenGL
Рассмотрев основные вопросы функционирования приложения и его взаимодействия с операционной системой, мы можем перейти к изучению собственно OpenGL. Например, в программе с помощью команд OpenGL окно формы окрашивается в голубоватый цвет. Во-первых, обратите внимание на то, что список uses дополнен модулем OpenGL - это программист должен сделать сам Раздел private описания класса формы содержит строку
hrc: HGLRC; // ссылка на контекст воспроизведения
Смысл этой величины мы рассмотрели в предыдущем разделе. Обработчик события OnCreate формы содержит следующие строки:
SetDCPixelFormat(Canvas. Handle); //задаем формат пиксела
hrc: = wglCreateContext(Canvas. Handle); //
создаем контекст
Первая строка - обращение к описанной в этом же модуле пользовательской процедуре, задающей формат пиксела
procedure SetDCPixelFormat (hdc: HDC);
var
pfd: TPixelFormatDescriptor;
nPixelFormat: Integer;
begin
FillChar (pfd, SizeOf (pfd), 0);
nPixelFormat: = ChoosePixelFormat (hdc, @pfd);
SetPixelFormat (hdc, nPixelFormat, @pfd);
end;
По поводу формата пиксела мы
подробнее поговорим в
wglMakeCurrent (Canvas. Handle, hrc); // установить контекст
glClearColor (0. 5, 0. 5, 0. 75, 1. 0); // цвет фона
glClear (GL_COLOR_BUFFER_BIT); // очистка буфера цвета
wglMakeCurrent (0, 0); // освободить контекст
Первая строка делает контекст воспроизведения текущим, т.e. занимает его для последующего вывода. Далее задаем цвет фона. Следующую строку будем понимать как очистку экрана и окрашивание его заданным цветом. После работы освобождаем контекст.
Замечание
Согласно
справке, для освобождения контекста воспроизведения
оба параметра должны быть установлены
в NULL, но хотя компилятор и пропустит такие
значения, во время выполнения получим
ошибку "Invalid variant type conversion", так что
будем всегда для освобождения контекста
задавать эти значения нулевыми. Обработка
события onDestroy формы состоит из одной строки:
wglDeleteContext (hrc);
Тем самым мы по завершении работы приложения удаляем контекст воспроизведения, освобождая память.
Замечание
Очень важно
запомнить, что процедуры и функции, имена
которых начинаются на gl или glu, т.e. команды
OpenGL, имеют какой-либо результат только
при установленном контексте воспроизведения
Вернемся к команде glclearcolor, определяющей цвет фона. У нее четыре аргумента, вещественные числа, первые три из которых задают долю красного, зеленого и синего в результирующем цвете. Четвертый аргумент я задал его значение равным единице. Можете варьировать это значение произвольно, в данном примере это никак не скажется, так что пока можете просто не обращать внимания на этот аргумент. Согласно справке, все четыре аргумента функции glclearColor имеют тип GLclampf, соответствующий вещественным числам в пределах от нуля до единицы. О типах OpenGL подробнее если вы используете Delphi версии три или четыре, вы, возможно, столкнетесь с одной небольшой проблемой. Если запускать проекты, использующие OpenGL, под управлением среды Delphi, программа может случайным образом аварийно завершаться. Оборот "случайным образом" здесь я употребил постольку, поскольку один и тот же проект может привести к аварийному завершению, а может и работать вполне успешно. Я сталкивался с этой проблемой на компьютерах с различной конфигурацией и с различными версиями операционной системы, и, по-видимому, она связана с некорректным взаимодействием среды Delphi c драйверами. Если подобная проблема возникла и у вас, я рекомендую просто не запускать под управлением среды проекты, использующие OpenGL, a запускать собственно откомпилированные модули. В пятой версии Delphi такая ситуация не возникала, так что, по-видимому, этот недостаток разработчиками выявлен и устранен.
Формат пикселя
Напомню, ссылка на контекст устройства содержит характеристики устройства и средства отображения. Упрощенно говоря, получив ссылку на контекст устройства, мы берем в руки простой либо цветной карандаш или кисть с палитрой в миллионы оттенков. Сервер OpenGL, прежде чем приступать к работе, также должен определиться, на каком оборудовании ему придется работать. Это может быть скромная персоналка, а может быть и мощная графическая станция.