Концепції програмування. Графічна система OpenGL

2



МІНІСТЕРСТВО ОСВІТИ УКРАЇНИ

Бердичівський політехнічний коледж















Контрольна робота

з предмета “ Комп’ютерна графіка "

(варіант №7)







Виконала: студентка групи ПЗС-504

КАЛІНІНА І.М.

Перевірив

викладач: КОЗІК В.Ю.

















м. Бердичів

2007 р


Основні типи проекції



Це питання часто задають програмісти при порівнянні додатків, створених в різних середовищах програмування, що починають. Дійсно, мінімальний додаток, створений в різних версіях Delphi, може досягати від 170 до 290 Кбайт. Це дуже велика цифра для операційного середовища Windows, в компіляторах C++ вона складає порядка 40 Кбайт. Звичайно, це не катастрофічна проблема, коли місткості накопичувачів вимірюються гігабайтами, і середній користувач, як правило, не звертає уваги на розмір файлу. Незручності виникають, наприклад, при розповсюдженні додатків по мережі. Використовування пакетів значно знімає гостроту проблеми для масштабних проектів, але сумарна вага додатку і пакетів, що використовуються, все одно значна. Коротка відповідь на питання, поставлене в заголовку розділу, полягає в тому, що великий розмір додатків, що відкомпілювалися, є платнею за неймовірну зручність проектування, Delphi, що надається. Архітектура середовища програмування, RTTI, компонентний підхід - все це перетворює Delphi на дивно могутній інструмент. За допомогою Delphi легко написати додатки, в яких, наприклад, динамічно створюються інтерфейсні елементи будь-якого типу (класу). Однак, додатку середнього рівня не використовують і не потребують цих могутніх можливостей. Чи часто вам зустрічалися додатки, що пропонують користувачу перед уведення-виведенням даних визначитися, за допомогою яких інтерфейсних елементів здійснюватиметься введення або висновок, а потім розмістити ці елементи на вікні в зручних місцях? І користувачі, і розробники в таких засобах, як правило, не випробовують необхідності. Проте модуль, що відкомпілювався, містить в собі весь той код, завдяки якому в Delphi так легко проводити маніпуляції з властивостями і методами об'єктів. Наприклад, якщо проглянути вміст модуля, що відкомпілювався, то ми зустрінемо в ньому фрази, що мають до власне операційної системи непряме відношення, наприклад, "OnKeyDown" або інші терміни Delphi. Справа тут не в недосконалості компілятора, компілятор Delphi оптимізує код чудово, справа в самій ідеології Delphi. Дуже часто після з'ясування цього факту програмісти, що починають, задають питання, як позбутися RTTI, від включення "непотрібного" коду у виконувані модулі. На жаль, це зробити неможливо. Кардинально проблема розв'язується тільки через відмову від використовування бібліотеки класів Delphi, т. e. програмування без VCL. Після того, як ми торкнулися до основоположних термінів і понять операційної системи Windows "повідомлення" і "посилання на вікно", ми зможемо опуститися нижче за рівень об'єктно-орієнтованого програмування, VCL і RAD-технологій. Потрібне це з чотирьох причин. По-перше, додатки, активно використовуючі графіку, частіше за все не мають потреби і не використовують багатство бібліотеки класів Delphi. Таким додаткам, як правило, достатньо вікна як полотно, таймера і обробників миші і клавіатури. По-друге, при програмуванні, заснованому тільки на використовуванні функцій API, виходять мініатюрні додатки. Модуль, що відкомпілювався, не обтяжується кодом опису компонентів і кодом, пов'язаним з концепціями ООП. По-третє, для розуміння прийомів, що використовуються для збільшення швидкості відтворення, потрібно мати уявлення про справжній пристрій Windows-програми. Наприклад, щоб команди перемальовування вікна виконувалися швидше, ми уникатимемо використовування методів Refresh і paint форми. По-четверте, це необхідне для розуміння дій, вироблюваних для підключення OpenGL. Ця бібліотека створювалася в епоху становлення ООП, і її поки не торкнулися подальші нововведення в технології програмування.



Мінімальна Windows-програма 



Подивитеся на проект з підкаталогу Ex07 - код мінімальної програми Windows. Мінімальної вона є в тому значенні, що в результаті виходить просто порожнє вікно. Також її можна назвати мінімальною програмою тому, що модуль, що відкомпілювався, займає всього близько 16 Кбайт. Додаток меншого розміру, що має власне вікно, одержати вже ніяк не вдасться, хоча можуть бути і програми ще коротше і менше, наприклад, така:



program p; uses Windows;

begin MessageBeep (mb_ok) end.



Єдине, що робить ця програма, - подача звукового сигналу. Проте повернемося до коду проекту з підкаталогу Ex07. Перше, на що необхідно звернути увагу: в списку uses вказано тільки два модулі - windows і Messages. Це означає, що в програмі використовуються виключно функції API, і як наслідок - довгий С-подібний код. І дійсно, перенести цю і подібні їй програми на Із зажадає небагато зусиль. Дана програма для нас украй важлива, оскільки вона стане шаблоном для деяких інших прикладів. Програму умовно можна розділити на дві частини - опис віконної функції і власне головна програма. У віконній функції задається реакція додатку на повідомлення Windows. Саме віконну функцію необхідно доповнювати кодом обробників повідомлень для розширення функціональності додатку. Щось подібне ми маємо в подія-орієнтованому програмуванні, але, звичайно, в абсолютно іншій якості. В мінімальній програмі задана реакція на єдине повідомлення wm_Destroy. На решту все повідомлень викликається функція ядра операційної системи DefWindowProc, що здійснює стандартну реакцію вікна. Одержане вікно поводиться звичайно, його можна змінювати в розмірах, мінімізувати, максимізувати. Додаток реагує також звичним чином, проте необхідності кодувати всі ці дії немає. У принципі, можна видалити і обробку повідомлення wm_Destroy, але в цьому випадку додаток після завершення роботи залишить слід в пам'яті, що з'їдає ресурси операційної системи. Значення змінної-результату обнуляється на початку опису віконної функції для запобігання зауваження компілятора про можливу неініціалізацію змінною. Головна програма починається з того, що визначаються атрибути вікна. Термін "структура", що перейшов в Delphi з мови З, відповідає терміну "запис". Термін "клас вікна" має до термінології об'єктно-орієнтованого програмування швидше наближене, ніж безпосереднє відношення. Значення, що задаються полям структури, визначають властивості вікна В цій програмі я задав значення всім полям, що, у принципі, робити не обов'язково, ми зобов'язані вказати адресу віконної функції, а всю решту значень можна брати за умовчанням. Проте в цьому випадку вікно виглядатиме або поводитиметься незвичайно. Наприклад, при запуску будь-якого додатку операційна система задає курсор для нього у вигляді пісочного годинника, і якщо ми не станемо явно задавати вид курсора в класі вікна, курсор вікна додатку так і залишиться у вигляді пісочного годинника. Після заповнення полів класу вікна його необхідно зареєструвати в операційній системі. В прикладі я аналізую результат, що повертається функцією Registerclass Це також робити не обов'язково, неможливість реєстрації класу вікна - ситуація украй рідкісна за умови коректного заповнення його полів. Наступні рядки можна інтерпретувати як "створення конкретного екземпляра на базі зареєстрованого класу" Дуже схоже на ООП, але схожість ця вельми приблизна і пояснюється тим, що перша версія Windows створювалася в епоху первинного становлення концепції об'єктно-орієнтованого програмування. При створенні вікна ми уточнюємо його деякі додаткові властивості - заголовок, положення, розміри і інше. Значення цих властивостей задаються аргументами функції createWindow, що повертає увагу, величину типа HWND - те саме посилання на вікно, що в Delphi називається Handle. Після створення вікна його можна відобразити - викликаємо функцію showWindow. Як правило, вікно відразу після цього перемальовують викликом функції updateWindow - дія теж необов'язкова, але для коректної роботи додатку видаляти цей рядок небажано. Далі слідує цикл обробки повідомлень, найважливіше місце в програмі, фактично це і є власне робота додатку. В ньому відбувається діалог додатку з операційною системою: витягання чергового повідомлення з черги і передача його для обробки у віконну функцію. Як вже мовилося, функції API і повідомлення - теми дуже обширні, і я не ставлю за мету вичерпно освітити ці теми. В розумних об'ємах я зможу висловити тільки найнеобхідніше, а більш докладну інформацію можна одержати в оперативній допомозі Delphi. На жаль, версії Delphi 3 і 4 поставляються з системою допомоги, не набудованої належним чином для отримання інформації по функціях API і командах OpenGL. Якщо судити за змістом допомозі, то може скластися враження, що ці розділи в ній взагалі відсутні. Можна або настроювати довідкову систему самостійно, або, що я і пропоную, користуватися контекстною підказкою - для отримання відомостей по будь-якій функції API достатньо поставити курсор на відповідний рядок і натискувати клавішу <F1>.

В п'ятій версії Delphi система допомоги набудована цілком задовільно, а самі файли допомоги оновлені.

До речі, звертаю увагу, що описи функцій приводяться з файлів фірми Microsoft, призначених головним чином для програмістів, що використовують мову З, тому одержану інформацію необхідно інтерпретувати в контекст Delphi. Код мінімальної програми я детально прокоментував, так що сподіваюся, що всі виниклі питання ви зможете дозволити за допомогою моїх коментарів.

Отже, в додатках Windows насправді управління постійно знаходиться в циклі обробки повідомлень, подія-орієнтована схема як така відсутня При отриманні вікном чергового повідомлення управління передається віконній функції, в якій задається реакція на нього, або викликається функція API DefWindowProc для реакції, прийнятої за умовчанням.

Приведений приклад лише віддалено нагадує те, що ми маємо в Delphi - подія-орієнтоване програмування, засноване на об'єктах. Звичайно, вчинити шлях, зворотний історично пройденому, нелегко. Відмовитися від бібліотеки VCL при написанні програм на Delphi для багато кого виявляється непосильним. Винагородою тут може стати мініатюрність одержаних програм: як ми бачимо, мінімальна програма зменшилася мінімум вдесятеро, швидше завантажується, виконується і швидше вивантажується з пам'яті. Такий розмір нелегко, а деколи і неможливо одержати в будь-якому іншому компіляторі, окрім як в Delphi. До того ж проекти, в списку uses яких коштують тільки windows і Messages, компілюються ще стрімкіше, не дивлячись на страхітливу масивність коду. А зараз подивитеся проект з підкаталогу Ex08, де вікно доповнено кнопкою і міткою. В коді з'явилися нові рядки, а найпростіші маніпуляції, наприклад, зміна шрифту мітки, ще зажадають додаткові рядки. Подібний обширний код звичайно бентежить новачків, тому я не зловживатиму такими прикладами і обмежуся тільки найнеобхіднішими для нас темами - як створити обробник миші, клавіатури і таймера. Я не примушуватиму вас писати всі програми таким виснажливим способом, нам просто потрібно мати уявлення про роботу базових механізмів, щоб краще розуміти, що робить за нас Delphi і що необхідно зробити, щоб підключити OpenGL до наших проектів.



Поняття контексту відображення та пристрою в бібліотеці Opengl



Ми вже знаємо, що посилання на контекст пристрою - це величина типа HDC. Для її отримання можна викликати функцію GetDC, аргументом якої є посилання на потрібне вікно. Посиланню на контекст пристрою відповідає властивість canvas. Handie форми, принтера і деяких компонентів Delphi. Яке ж все-таки значення контексту пристрою, якщо він і такий пов'язаний з однозначно певним об'єктом - вікном, областю пам'яті або принтером, і навіщо передавати додатково якусь інформацію про однозначно певний об'єкт? Для відповіді на ці питання звернемо увагу на чудову властивість висновку в Windows, що полягає в тому, що одними і тими ж функціями здійснюється висновок на різні пристрої. Рядки програми



Forml. Canvas. Ellipse (0, 0, 100, 100);

І

Printer. BeginDoc;

Printer. Canvas. Ellipse (0, 0, 100, 100);

Printer. EndDoc;



малюють один і той же круг як на поверхні форми, так і в роздруковуваному документі, т. e. на різних пристроях, причому якщо ми виводитимемо різнокольорову картинку на монохромний принтер, він справиться з цією задачею, передаючи кольори відтінками сірого. Навіть якщо ми малюємо тільки на полі форми, ми маємо справу з різними пристроями - нам невідомо, яка графічна платня комп'ютера і які характеристики поточної установки настройок екрану. Наприклад, маючи в своєму розпорядженні більше 16 мільйонів кольорів, додаток не піклується про відображення цієї багатої палітри на екрані, що має свій в розпорядженні всього 256 кольори. Такі питання додаток перекладає на плечі OpenGL Графіка в проектах Delphi раціонної системи, вирішальної їх за допомогою використовування драйверів пристроїв Для того, щоб скористатися функціями відтворення Windows, додатку необхідно тільки вказати посилання на контекст пристрою, що містить засоби і характеристики пристрою висновку. Довідковий файл Win32 Programmer's Reference фірми Microsoft, що поставляється у складі Delphi, про контекст пристрою повідомляє наступне "Контекст пристрою є структурою, яка визначає комплект графічних об'єктів і пов'язаних з ними атрибутів і графічні режими, що впливають на висновок Графічний об'єкт включає олівець для зображення лінії, кисть для зафарбовування і заповнення, растр для копіювання або прокрутки частин екрану, палітру для визначення комплекту доступних кольорів, області для відсікання і інших операцій, маршрут для операцій малювання" В OpenGL є аналогічне посиланню на контекст пристрою поняття посилання на контекст відтворення Графічна система OpenGL, як і будь-який інший додаток Windows (хоча і розміщене в DLL), також потребує посилання на пристрій, на який здійснюватиметься висновок Це спеціальне посилання на контекст відтворення, - величина типа HGLRC (Handle openGL Rendering Context, посилання на контекст відтворення OpenGL).

Контекст пристрою Windows містить інформацію, що відноситься до графічних компонентів GDI, а контекст відтворення містить інформацію, що відноситься до OpenGL, т e грає таку ж роль, що і контекст пристрою для GDI Зокрема, згадані контексти є сховищами стану системи, наприклад, бережуть інформацію про поточний колір олівця.



Засобами бібліотеки Opengl побудувати сферу



Після відображення команд в програмі Delphi сфера матиме такий вигляд, який вказаний в моєму завданні нижче на (рис.1, рис.2, рис.3)





рис. №1




рис. № 2





рис. №3



Листинг програми матиме такий вигляд:

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

OpenGL, Menus;

type

TfrmGL = class (TForm)

procedure FormCreate (Sender: TObject);

procedure FormPaint (Sender: TObject);

procedure FormDestroy (Sender: TObject);

procedure FormKeyDown (Sender: TObject; var Key: Word;

Shift: TShiftState);

procedure FormResize (Sender: TObject);

procedure FormKeyPress (Sender: TObject; var Key: Char);

private

DC: HDC; // контекст пристрою

hrc: HGLRC; // контекст відображення

ry: GLfloat; // зміна координати по У

tx: GLfloat; // зміна координати по Х

end;

var

frmGL: TfrmGL;

mode: (POINT, LINE, FILL) = FILL; // режими відображення обєкта

mx,my: byte; // коефіцієнти збільшення/зменшення

implementation

uses DGLUT;

{$R *. DFM}

procedure TfrmGL. FormPaint (Sender: TObject);

begin

glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // очищення буферу кольору

glPushMatrix; // заповнюємо систему координат

glScalef (my/mx, my/mx, my/mx); // виконуємо маштабування

glRotatef (ry, 0.0, 1.0, 0.0); // виконуємо потовот

glTranslatef (tx, 0.0, 0.0); // виконуємо перенесення

case mode of // вибираємо режим відображення

POINT: glPolygonMode (GL_FRONT_AND_BACK, GL_POINT);

LINE: glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);

FILL: glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);

end;

glutSolidSphere (1.5, 20, 20); // будуємо сферу

glScalef (mx/my, mx/my, mx/my); // повертаємо систему в початкове полож

glPopMatrix; // повертаємо систему в попереднє положення

SwapBuffers (DC); // відображуємо на екрані

end;

procedure SetDCPixelFormat (hdc: HDC);

var

pfd: TPixelFormatDescriptor;

nPixelFormat: Integer;

begin

FillChar (pfd, SizeOf (pfd), 0);

pfd. dwFlags: = PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;

nPixelFormat: = ChoosePixelFormat (hdc, @pfd);

SetPixelFormat (hdc, nPixelFormat, @pfd);

end;

procedure TfrmGL. FormCreate (Sender: TObject);

begin

DC: = GetDC (Handle);

SetDCPixelFormat (DC);

hrc: = wglCreateContext (DC);

wglMakeCurrent (DC, hrc);

glClearColor (0.5, 0.5, 0.75, 1.0); // цвет фона

glLineWidth (1.5);

glEnable (GL_LIGHTING);

glEnable (GL_LIGHT0);

glEnable (GL_DEPTH_TEST);

glEnable (GL_COLOR_MATERIAL);

glColor3f (1.0, 0.0, 0.0);

ry: = 0.0;

tx: = 0.0;

mx: =10;

my: =10;

end;

procedure TfrmGL. FormDestroy (Sender: TObject);

begin

wglMakeCurrent (0, 0);

wglDeleteContext (hrc);

ReleaseDC (Handle, DC);

DeleteDC (DC);

end;

procedure TfrmGL. FormKeyDown (Sender: TObject; var Key: Word;

Shift: TShiftState);

begin

If Key = VK_ESCAPE then Close;

If Key = VK_LEFT then begin

ry: = ry + 2.0;

InvalidateRect (Handle, nil, False);

end;

If Key = VK_RIGHT then begin

ry: = ry - 2.0;

InvalidateRect (Handle, nil, False);

end;

If Key = VK_UP then begin

tx: = tx - 0.1;

InvalidateRect (Handle, nil, False);

end;

If Key = VK_DOWN then begin

tx: = tx + 0.1;

InvalidateRect (Handle, nil, False);

end;

If Key = 49 then begin

mode: = POINT;

InvalidateRect (Handle, nil, False);

end;

If Key = 50 then begin

mode: = LINE;

InvalidateRect (Handle, nil, False);

end;

If Key = 51 then begin

mode: = FILL;

InvalidateRect (Handle, nil, False);

end;

end;

procedure TfrmGL. FormResize (Sender: TObject);

begin

glViewport (0, 0, ClientWidth, ClientHeight);

glMatrixMode (GL_PROJECTION);

glLoadIdentity;

glFrustum (-1, 1, - 1, 1, 2,9);

glMatrixMode (GL_MODELVIEW);

glLoadIdentity;

 // этот фрагмент нужен для придания трёхмерности

glTranslatef (0.0, 0.0, - 5.0); // перенос объекта - ось Z

glRotatef (30.0, 1.0, 0.0, 0.0); // поворот объекта - ось X

glRotatef (70.0, 0.0, 1.0, 0.0); // поворот объекта - ось Y

InvalidateRect (Handle, nil, False);

end;


Для попереднього практичного завдання вашого варіанту забезпечити операцію масштабування використовуючи клавіши “+” та “-“

Для попереднього практичного завдання вашого варіанту забезпечити операцію масштабування використовуючи клавіши “+” та “-“

Потім для точного виконання завдання виконала слідуючий алгоритм дій при цьому використала згідно варіанту клавіші "+" та "-", що по умові завдання виконують наближення та відділення фігури на фоні:



procedure TfrmGL. FormKeyPress (Sender: TObject; var Key: Char);

begin

if key = '-' then mx: =mx+1;

if key = '+' then mx: =mx-1;

InvalidateRect (Handle, nil, False);

end;

end.


Список використаної літератури



С.В. Глушаков, Г.А. Крабе Компютерная графика, Харьков 2002

Блінова Т.О., Порєв В.М. Комп’ютерна графіка / За ред. В.М. Горєва. - К.: Видавництво “Юніор”, 2004.

OpenGl, технология ставшая символов, Учебник в примерах.

Конспект лекцій.

Мережа Інтернет.