Програмування в СІ

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Кафедра: Автоматика та Інформаційні Технології
ПРОГРАМУВАННЯ В СІ роботи в графічному режимі

ЗМІСТ
1. ПЕРЕГЛЯД ГРАФІЧНИХ ФУНКЦІЙ3
1.1. Загальні відомості
1.2. Ініціалізація графічного драйвера і режиму
1.3. Робота з растром точок
1.4. Управління кольором
1.5. Базові функції доступу до відеопам'яті
1.6. Графічні примітиви
1.7. Висновок графічного тексту
2. ПРИЙОМИ ПРОГРАМУВАННЯ ГРАФІЧНОГО РЕЖИМУ
2.1. Підключення графічної бібліотеки
2.2. Ініціалізація графічного режиму
2.3. Включення драйвера і шрифтів в виконуваний файл
2.4. Малювання геометричних фігур
2.5. Виділення пам'яті під великі одномірні масиви
2.6. Висновок числової інформації
2.7. Затримка екрану
2.8. Реакція програми на натиснення конкретної клавіші
2.9. Організація введення числової інформації
2.10.Проверка виходу аргументу функції з ОДЗ
2.11.Графіческая та математична системи координат
2.12.Іспользованіе двох відеосторінок
2.13.Рісованіе зображень в bmp-форматі
2.14.Работа з мишею
3. ЗАВДАННЯ ДЛЯ ЛАБОРАТОРНОЇ РОБОТИ
3.1. Зоряне небо
3.2. Снігопад
3.3. Малювання графіка функції
3.4. Обертання зірки
СПИСОК

1. ПЕРЕГЛЯД ГРАФІЧНИХ ФУНКЦІЙ

1.1. Загальні відомості

Графічний режим персональних комп'ютерів є більш привабливим, ніж текстовий режим. Серйозні програмні додатки, написані під DOS, як правило, мають графічну оболонку.
У найзагальніших рисах робота з дисплеєм ПК в графічному режимі може бути представлена ​​наступним чином. Екран дисплейного монітора представляється як набір окремих точок - пікселів (pixels, від англійського picture elements), що утворить прямокутний растр. Число пікселів визначає роздільну здатність (дозвіл) графічної системи і зазвичай відбивається парою чисел, перше з яких показує кількість пікселів в рядку, а друге - кількість рядків. Кожному пікселю екрану ставиться у відповідність фіксовану кількість бітів (атрибут пікселя) в деякій області адресного простору центрального мікропроцесора ПК. Ця область, звана відеопам'яттю, як правило, є частиною дисплейного адаптера (відеоадаптера) - спеціального пристрою, який керує роботою монітора. Відеоадаптер, зокрема, здійснює циклічне відтворення вмісту відеопам'яті на екрані монітора. Причому зображення кожного пікселя визначається поточним значенням його атрибуту. Такий підхід отримав назву бітової карти - bit-mapped graphics. Програмі, виконується на ПК в графічному режимі, доступні для читання і запису всі пікселі відеопам'яті.
У ряді випадків можливе одночасне існування у відеопам'яті двох або більше областей однакової структури, кожна з яких містить атрибути всіх пікселів екрана. Такі області називаються сторінками. У певний момент часу будь-яка зі сторінок може відображатися відеоадаптером на дисплеї, займаючи при цьому весь екран. Наявність сторінок дозволяє програмі швидко змінювати зображення на екрані, просто перемикаючись з однієї сторінки на іншу. Зокрема, це дає можливість проводити всю "чорнову роботу" з підготовки графічного зображення на неотображаемой в даний момент часу сторінці, уникаючи появи на екрані побічних графічних ефектів.
Графічне відображення, що виникає на екрані монітора, є результатом виконання наступних дій:
· Атрибути пікселів зображення повинні бути завантажені в пам'ять. Зазвичай цю роботу здійснюють спеціальні функції DOS або BIOS, однак можлива й пряма робота з відеопам'яттю;
· Спеціальна схема відеоадаптера забезпечує періодичне зчитування відеопам'яті і перетворення значень атрибутів пікселів в послідовність сигналів, керуючих монітором.
У персональних комп'ютерах використовуються різні типи дисплейних адаптерів (CGA, EGA, VGA і ін), більшість з яких може працювати в різних режимах (текстових та графічних), званих також відео (video modes). Графічні режими одного адаптера різняться роздільною здатністю, кількістю квітів, кількістю сторінок відеопам'яті і способом їх адресації. Установкою графічного режиму управляє переривання BIOS з номером 10h.
Оскільки обсяг сторінки відеопам'яті обмежений, то кількість бітів, що припадають на один піксель, перебуває у зворотній залежності від загальної кількості пікселів на екрані. Зазвичай атрибут пікселя складається з 1, 2, 4 або 8 біт, у залежності від графічного режиму. Всі пікселі, що мають однакове значення атрибуту, відображаються на екрані однаковим чином.
Якщо атрибуту кожного пікселя у відеопам'яті відводиться тільки один біт, то графіка буде двокольорового, наприклад чорно-білої (конкретні кольору залежать від типу монітора). Якщо кожен піксель в графічному режимі представляється n бітами, то в такому режимі є можливість одночасно представити на екрані N_pallette = 2 n відтінків кольору (палітра режиму). У деяких графічних системах прийнято в цьому випадку говорити про наявність n площин кольорів (color planes).
У дисплейних адаптерах з монохромним монітором значення атрибуту управляє інтенсивністю одного електронного променя, тобто яскравістю точки на екрані, а з кольоровим монітором - інтенсивністю трьох променів, складових колірні компоненти зображення пікселя. Як правило, використовується поділ кольору на RGB-компоненти - червону, зелену і синю. Якщо кожна компонента має N градацій, то загальне число колірних відтінків для такого адаптера становить N_colors = N 3, при цьому в число колірних відтінків включаються чорний, білий і градації сірого.
Кольоровий відеоадаптер має схему, яка здійснює під час розгортки кадру перетворення значення атрибуту кожного пікселя в сигнали управління інтенсивністю електронних променів монітора, що відповідають за RGB-компоненти. Роботу схеми можна уявити таблицею, по кожному входу якої зберігається опис кольору, використовуваного адаптером при виведенні на екран всіх пікселів, значення атрибутів яких рівні номером цього входу. Така схема називається картою або таблицею кольорів. Якщо максимальний розмір пікселя в графічних режимах, підтримуваних даними адаптером, представляється m бітами, то таблиця квітів такого адаптера містить N_table = 2 m рядків (входів). Всі три колірні компоненти в карті кольорів представлені, як правило, двійковими числами однаковою розрядності. Спосіб кодування кольору залежить від типу відеоадаптера.
Програмне управління квітами пікселів на екрані дисплея може здійснюватися без змін значень атрибутів пікселів у відеопам'яті. Для цього потрібно завантажити відповідні значення RGB-компонент у таблицю квітів по входу з номером, рівним значенню потрібного атрибуту. Зміни мапи кольорів негайно відображаються на екрані зміною кольору пікселів.

1.2. Ініціалізація графічного драйвера і режиму

Графічна система складається з ядра і великої бібліотеки графічних функцій graphics.lib (її потрібно підключати при компонуванні програмного модуля). При створенні програми, що звертається до графічних функцій, в текст програми потрібно включити файл, що містить прототипи функцій, константи, типи даних і різні перелічувані:
# Include <graphics.h>
Графічний інтерфейс фірми Borland International (BGI - Borland Graphics Interface) складається з двох компонент: постійного ядра графічної системи та набору графічних драйверів. Ядро графічної системи сприймає всі запити прикладної програми на виконання графічних функцій. Воно не залежить від типу підключеного дисплейного адаптера. Апаратно-залежною частиною є графічні драйвери, що здійснюють інтерфейс між ядром системи і конкретним дисплейним адаптером.
Графічні драйвери містяться в окремих файлах з розширенням. Bgi. Кожен файл містить бінарний образ (binary image) драйвера для одного або декількох близьких за типом адаптерів. Для використання в програмі за кожним драйвером закріплений постійний номер, якому відповідає макропідстановки, наприклад, EGA або VGA.
Графічні драйвери підтримують багато (але не всі) графічні режими дисплейних адаптерів, передбачені системою BIOS. Для вказівки в програмах графічних режимів, як і для драйверів, передбачені макропідстановки (EGALO, EGAHI, VGAHI та інші).
Перш ніж звертатися до графічних функцій, програма повинна вибрати графічний драйвер, відповідний дисплейний адаптер, і підключити його до ядра графічної системи. Графічна бібліотека містить функцію detectgraph, призначену для тестування апаратури й автоматичного вибору придатного драйвера і графічного режиму. Прототип цієї функції -
void far detectgraph (int far * graph_driver, int far * graph_mode);
Ця функція через свої аргументи повертає номер графічного драйвера і номер графічного режиму, що забезпечує максимальне для адаптера дозвіл. Повернуті цією функцією значення в подальшому можуть передаватися функції ініціалізації графічної системи initgraph (але можна для ініціалізації вибрати і інший режим, підтримуваний даними драйвером).
Якщо при тестуванні апаратури дисплейного адаптера не виявлено, то функція graphresult повертає значення -2. Функція graphresult повертає поточне значення внутрішньої змінної, що містить код завершення роботи графічних функцій. Її прототип
int far graphresult (void);
Негативне значення коду завершення, встановлене будь-якої графічної функцією, зберігається у внутрішній змінної аж до виклику функції graphresult, після чого воно обнуляється.
Є можливість отримати рядок, що містить опис будь-якого з допустимих кодів завершення графічних функцій. Для чого існує функція grapherrormsg. Прототип функції -
char far * grapherrormsg (int error_code);
Якщо цієї функції передати значення, що повертається функцією graphresult, то можна отримати повідомлення про код завершення останньої графічної функції.
Графічний драйвер повинен бути поміщений в оперативну пам'ять до того, як відбудеться звертання до якої-небудь функції графічної бібліотеки.
Найпростішим способом включення драйвера в програму є його автоматичне завантаження за допомогою функції initgraph з прототипом
void initgraph (int far * graph_driver, int far * graph_mode, char far * path_to_bgi);
Аргументами даної функції є покажчики на змінні, що містять номер графічного драйвера, номер графічного режиму і шлях до BGI-файлу драйвера. Функція initgraph шукає на диску BGI-файл, що містить потрібний драйвер, завантажує файл цілком в динамічно виділяється пам'ять і налаштовує ядро ​​системи на роботу з цим драйвером. Якщо ініціалізація пройшла успішно, функція graphresult поверне нульове значення GR_Ok, в іншому випадку - одне з негативних значень, визначених у файлі graphics.h.
Функція
void far closegraph (void)
припиняє роботу графічної системи. Вона звільняє всю пам'ять, виділену за запитами графічних функцій, очищає буфер відеоадаптера і відновлює текстовий режим, що існував перед ініціалізацією графічної системи.
Приклад автоматичного завантаження драйвера і ініціалізації
системи:
int main (void)
{
int gd, gm, err;
detectgraph (& gd, & gm) / * визначення номера драйвера і режиму * /
err = graphresult (); / * отримання коду завершення * /
if (err) {printf ("\ n% s", grapherrormsg (err)); return 1;}
initgraph (& gd, & gm, "c: \ \ borlandc \ \ bgi") / * ініціалізація системи * /
err = graphresult (); / * отримання коду завершення * /
if (err) {printf ("\ n% s", grapherrormsg (err)); return 2;}
/ * ................ Різні оператори ..............*/
closegraph (); / * завершення роботи системи * /
return 0;
}
Можна не визначати номери драйвера і режиму тестуванням апаратури, а ставити їх за бажанням, головне при цьому дотримуватися відповідність обраного драйвера і наявного в розпорядженні відеоадаптера. Наведений вище приклад можна змінити тоді наступним способом:
int main (void)
{
int gd = VGA, gm = VGAHI, err;
initgraph (& gd, & gm, "c: \ \ borlandc \ \ bgi");
err = graphresult ();
if (err)
{
printf ("\ n% s", grapherrormsg (err));
return 1;
}
/ * ................ Різні оператори ..............*/
closegraph ();
return 0;
}
Головним недоліком автоматичного завантаження драйвера за допомогою функції initgraph є те, що вона звертається до диску для читання BGI-файлу під час виконання програми. Альтернативою автоматичної завантаженні графічного драйвера є його статичне включення на етапі побудови програми. Попередньо бінарний файл драйвера. Bgi повинен бути перетворений на звичайний об'єктний файл типу. Obj необхідні інструменти bgiobj.exe. До речі, дана утиліта використовується також для конвертації chr-файлів з графічними шрифтами в об'єктні модулі. Отримані об'єктні модулі підключаються на етапі компоновки.
У програмі, перш ніж ініціалізувати графічну систему, необхідно потрібні драйвери зареєструвати, тобто повідомити графічній системі, що даний драйвер вже знаходиться в оперативній пам'яті. Для цього існує функція registerbgidriver, якій потрібно повідомити місце розташування драйвера:
int registerbgidriver (void (* driver) (void));
Аргумент функції - ім'я покажчика на місце в пам'яті, що містить реєстрований драйвер. Імена подібних покажчиків вже визначені в об'єктних файлах, створених за допомогою утиліти bgiobj.exe. Нижче наведені прототипи функцій, імена яких потрібно вживати для стандартних драйверів:
void CGA_driver (void);
void EGAVGA_driver (void);
void IBM8514_driver (void);
void Herc_driver (void);
void ATT_driver (void);
void PC3270_driver (void).
Якщо реєстрація пройшла успішно, функція graphresult поверне нульове значення, у противному випадку -4. Після реєстрації драйвера можна ініціалізувати графічну систему за допомогою функції initfgraph, при цьому її третій параметр не використовується (передається нульова рядок "").
Приклад статичної завантаження драйвера та ініціалізації системи:
int main (void)
{
int gd, gm, err;
detectgraph (& gd, & gm);
err = graphresult ();
if (err)
{
printf ("\ n% s", grapherrormsg (err));
return 1;
}
registerbgidriver (EGAVGA_driver);
err = graphresult (); / * отримання коду завершення * /
if (err)
{
printf ("\ n% s", grapherrormsg (err));
return 1;
}
initgraph (& gd, & gm ,""); / * ініціалізація системи * /
if ((err = graphresult ())! = grOk)
{
printf ("\ n% s", grapherrormsg (err));
return 1;
}
/ * ................ Різні оператори ..............*/
closegraph (); / * завершення роботи системи * /
return 0;
}
Якщо графічна система активізовано і необхідно по ходу виконання програми переключитися на використання іншого графічного драйвера, то до повторного виклику функції initgraph необхідно скинути графічну систему функцією closegraph для звільнення всієї пам'яті, яку займала система.
Ім'я поточного графічного драйвера можна дізнатися за допомогою функції
char far * getdrivername (void);
Вона повертає покажчик на рядок, що містить ім'я активного в цей момент драйвера.
Максимальне значення номера графічного режиму, допустима для поточного графічного драйвера, можна дізнатися за допомогою функції
int far getmaxmode (void);
Поточне значення номера графічного режиму для активізованого драйвера повертає функція
int far getgraphmode (void);
За номером режиму можна отримати рядок з описом даного режиму для поточного драйвера. Це робиться за допомогою функції
char far * getmodename (int mode_number);
У графічній бібліотеці є функція визначення мінімально і максимально допустимих значень номери графічного режиму для графічного драйвера, номер якого їй передається (необов'язково активізованого)
void far getmoderange (int graph_driver, int far * min_mode, int far * max_mode);
Є дві функції, що дозволяють змінювати встановлений графічний режим без повторного звернення до функції initgraph і навіть переходити тимчасово в текстовий режим роботи відеоадаптера. Якщо потрібно перейти в інший графічний режим активізованого в даний момент драйвера, то можна скористатися функцією
void far setgraphmode (int new_mode);
Аргумент new_mode передає бажаний номер режиму для поточного драйвера і не повинен перевершувати максимально допустимий для цього драйвера значення.
Для тимчасового переходу в текстовий режим передбачена
функція
void far restorecrtmode (void);
Ця функція переводить відеоадаптер в той текстовий режим, в якому він перебував у момент останньої ініціалізації графічної системи, тобто безпосередньо перед зверненням до функції initgraph. З текстового режиму можна повернутися в графічний за допомогою функції setgraphmode.
При ініціалізації графічної системи всілякі параметри системи встановлюються за замовчуванням. Різні функції можуть міняти значення параметрів. Для того щоб у будь-який момент відновити характеристики системи, встановлені при її ініціалізації, існує функція
void far graphdefaults (void);
Перерахуємо дії, що виконуються цією функцією:
· Для виводу та відтворення зображення на екрані вибирається нульова сторінка відеопам'яті;
· Графічне вікно встановлюється розміром у всю сторінку;
· Поточна графічна позиція переміщається в точку (0,0);
· Встановлюються за замовчуванням кольори палітри, поточний малює колір (15) і колір фону (0);
· Встановлюється суцільний шаблон для малювання ліній і заповнення областей;
· Ініціалізується вбудований матричний шрифт зі стандартним розташуванням і позиціонуванням рядка.

1.3. Робота з растром точок

Растром точок називається двовимірна сукупність точок, що представляє екран дисплея.
Щоб у прикладній програмі мати можливість відобразити на екрані будь-яку з наявних сторінок відеопам'яті, в графічній бібліотеці передбачена функція
void far setvisualpage (int page);
Функція негайно відображає на екрані ту сторінку відеопам'яті, номер якої був їй переданий в якості аргументу. Сторінки нумеруються з нуля. Функція graphresult не реагує на спробу встановити неприпустимий номер сторінки. Вся відповідальність за правильність вказаного номера лежить на програмістові. Функція
void far setactivepage (int page);
не викликає перемальовування сторінки на екрані дисплея, але зате направляє весь наступний графічний висновок на ту сторінку, яка зазначена її аргументом. Як і при виклику попередньої функції, відповідальність за допустимість номера сторінки залишається на програмістові.
Сторінку відеопам'яті (і екран дисплея) можна представити як двовимірний прямокутний масив точок (пікселів). На цьому масиві точок вводиться система координат X, Y. Початок системи лежить у лівому верхньому кутку сторінки (екрана). Вісь X проходить по верхньому краю сторінки зліва направо, а вісь Y - по лівому краю зверху вниз. Ліва верхня точка сторінки має координати (0, 0), права нижня - координати (M-1, N-1), де M і N - розміри сторінок по горизонталі і вертикалі.
Визначити максимальні значення координат точок можна за допомогою функцій
int far getmaxx (void);
int far getmaxy (void);
Значення, що повертаються цими функціями, залежать тільки від поточного режиму, встановленого функціями initgraph або setgraphmode.
У розпорядженні програміста крім сторінки як цілого є ще одна двовимірна структура. Усередині основного масиву точок сторінки завжди виділений певний його подмассів, який називається графічним вікном (viewport). Графічне вікно є прямокутним масивом точок зі своєю системою координат. Початок цієї системи координат знаходиться в лівому верхньому кутку графічного вікна, а осі X і Y паралельні відповідним осях координат сторінки. Саме вікно має змінні розміри і може розташовуватися в будь-якому місці екрана. Заміна сторінки ніяк не впливає на характеристики вікна.
Багато функцій, що використовують координати точок, мають на увазі саме систему координат графічного вікна. Завдяки цьому з'являється можливість використовувати одну і ту ж програму для виконання деякої графічної роботи у вікні незалежно від того, в якому місці сторінки і навіть на якій саме сторінці вікно знаходиться в даний момент. Надалі при описі таких функцій завжди буде зазначатися, яка система координат (сторінки або вікна) мається на увазі.
При установці графічного режиму за допомогою функцій initgraph і setgraphmode відразу ж створюється і графічне вікно, що збігається за розмірами з усією сторінкою. Однак є можливість керувати розмірами і розташуванням графічного вікна динамічно. Робиться це за допомогою функції
void far setviewport (int left.int top, int right, int bottom, int clip);
Перші чотири аргументи - це координати лівої верхньої і правої нижньої меж графічного вікна в системі координат сторінки. Жодна з меж вікна не може лежати за межами сторінки. Останній аргумент встановлює режим відсікання: якщо він не нульовий, то кожен графічний висновок буде обрізатися на кордонах графічного вікна. Якщо при виклику фунції setviewport були невірно задані аргументи, то функція graphresult поверне -11 і збережеться попередня установка графічного вікна. Функція setviewport не змінює вміст сторінки відеопам'яті.
Для того щоб можна було в будь-який момент дізнатися про поточну установку графічного вікна, існує функція
void far getviewsettings (struct viewporttype far * viewport);
Ця функція поміщає параметри поточного вікна в структуру * viewport. Тип цієї структури визначений у файлі graphics.h:
struct viewporttype
{
int left, top, right, bottom;
int clip;
}
Повертані координати представлені в системі координат сторінки.
З графічним вікном пов'язане поняття поточної графічної позиції CP (current graphics position). Це графічний еквівалент курсору в текстовому режимі. Поточна графічна позиція сама собою ніяк не відображається на екрані і ідентифікує обраний піксель графічного вікна, до якого прив'язується дію деяких функцій, таких як креслення прямолінійних відрізків або виведення графічних текстів.
При установці нового графічного вікна поточна позиція автоматично поміщається в його початок координат. Для явної зміни положення поточної позиції використовуються функції
void far moveto (int x, int y);
void far moverel (int dx, int dy);
Перша поміщає CP за вказаними координатами графічного вікна. Друга переміщує CP на вектор (dx, dy).
Координати поточної графічної позиції в системі координат графічного вікна повертають функції:
int far getx (void);
int far gety (void);
При перевстановлення графічного вікна функцією setviewport вміст сторінки відеопам'яті не змінюється. Для очищення графічного вікна на активною в даний момент сторінці використовується функція
void far clearviewport (void);
CP при цьому переміщається у початок координат графічного вікна.
Схожа функція
void far cleardevice (void);
очищає всю активну сторінку. Установка графічного вікна при цьому не змінюється, а CP переміщається в його початок координат.
На багатьох моніторах піксель, який висвічується на екрані, має форму прямокутника, витягнутого по вертикалі. Це пояснюється тим, що на дисплеї сторінка відеобуфера відображається на весь екран, а пропорції екрану і сторінки в режимі максимальної роздільної здатності, як правило, не збігаються (виняток - монітори з адаптерами VGA, де в режимі з роздільною здатністю 640 х 480 крапок всі пікселі квадратні) . Така невідповідність призводить до виникнення анізотропності растра пікселів: горизонтальний і вертикальний відрізки, що містять однакове число пікселів, на екрані будуть виглядати, як відрізки різної довжини.
Тим не менш, кола та їх дуги малюються функціями бібліотеки правильно, тому що ці функції використовують зберігається у графічній системі коригувальний коефіцієнт пропорційності (aspect ratio), що враховує "ступінь неквадратні" пікселя. Щоб правильно намалювати квадрат, необхідно провести коригування кількості пікселів по його горизонтальної і вертикальної сторонам. Справжні пропорції пікселя на даному дисплеї можна дізнатися за допомогою функції
void far getaspectratio (int far * x_asp, int far * y_asp);
Ця функція через свої аргументи повертає шукане значення, причому * y_asp завжди встановлюється рівним 10 000, а величина * x_asp ≤ * y_asp. Ставлення * x_asp к * y_asp якраз і є ставлення горизонтального і вертикального розмірів пікселя. Тепер, якщо горизонтальна сторона квадрата представлена ​​відрізком довжиною X пікселів, то довжина вертикальної сторони повинна бути дорівнює значенню виразу
Y = (int) (X ∙ (float) (* x_asp) / (* y_asp)).
Зауважимо, що коефіцієнт "неквадратні" автоматично враховується лише функціями, які малюють кола та їх дуги, але ніяк не впливає на функції малювання еліпсів і їх дуг.

1.4. Управління кольором

Колірні можливості функцій графічної бібліотеки Borland C описуються в термінах кольорової палітри режиму - закону, за яким кожному допустимому значенню атрибута пікселя ставиться у відповідність колір, яким цей піксель буде відображатися на екрані.
Палітру режиму можна представити як таблицю, яка містить стільки рядків (входів), скільки значень допускається для атрибута пікселя в даному графічному режимі. Рядки палітри режиму нумеруються від нуля до N_palette-1. У рядку з номером k міститься код кольору, яким апаратура відеоадаптера відображає на екрані всі пікселі сторінки, атрибути яких рівні k. Нульовий вхід палітри режиму, крім того, визначає колір фону екрану.
Всі графічні режими можна розділити на три групи:
· Монохромні режими, в яких всі пікселі можуть бути двох кольорів - основного і фонового. Палітру таких режимів змінити неможливо;
· Кольорові режими з фіксованою палітрою. Для зміни палітри режиму потрібно міняти графічний режим, що призводить до втрати вмісту відеопам'яті;
· Графічні режими, що дозволяють динамічно (без втрати вмісту відеопам'яті) змінювати код кольору з будь-якого входу палітри режиму. До даних режимів належать режими драйверів EGA, VGA, IBM8514.
Механізм управління кольором в Borland C включає в себе важливий елемент - структуру даних, звану внутрішньої палітрою. При роботі в графічних режимах на всіх дисплейних адаптерах, крім VGA і IBM8514, вона містить коди квітів з таблиці кольорів адаптера. Роль внутрішньої палітри при роботі з адаптером VGA дещо інша і буде розглянута нижче. Драйвер IMB8514 взагалі не користується внутрішньої палітрою, тому надалі все, що буде говоритися про роботу з внутрішньої палітрою, не відноситься до цього драйверу. Не слід плутати внутрішню палітру (звичайну змінну структурного типу) графічної системи з палітрою режиму з законом перетворення значення пікселя в колір.
Визначення внутрішньої палітри як структури даних має вигляд:
# Define MAXCOLOR 15
struct palettetype
{
unsigned char size;
signed char colors [MAX_COLORS +1];
};
де size - це число рядків внутрішньої палітри, дозволене для використання в поточному графічному режимі, а colors - масив закодованих описів кольору.
Для всіх монохромних режимів і режимів з фіксованими палітрами допускається використання у внутрішній палітрі 16 кольорів, які в точності збігаються зі стандартними квітами текстового режиму. Кожен колір палітри кодується числом від 0 до 15. При ініціалізації таких графічних режимів значення кожного елемента масиву colors збігається з його індексом.
У режимах з динамічним управлінням внутрішня палітра містить 16 кольорів, коди яких можуть лежати в діапазоні від 0 до 63
(Тобто є можливість змінювати зміст внутрішньої палітри). Для 16 кодів квітів стандартного набору, встановлюються при ініціалізації цих режимів (як для драйвера EGA, так і VGA), визначений перераховувані тип EGA_COLORS, тобто стандартні коди кольорів мають символічні імена:
enum EGA_COLORS
{
EGA_BLACK = 0, EGA_BLUE = 1, EGA_GREEN = 2, EGA_CYAN = 3, EGA_RED = 4, EGA_MAGENTA = 5, EGA_BROWN = 20, EGA_LIGHTGRAY = 7, EGA_DARKGRAY = 56, EGA_LIGHTBLUE = 57, EGA_LIGHTGREEN = 58, ЕGA_LIGHTCYAN = 59, EGA_LIGHTRED = 60, EGA_LIGHTMAGENTA = 61, EGA_YELLOW = 62, EGA_WHITE = 63
};
Кількість динамічно керованих рядків таблиці кольорів для поточного графічного режиму можна визначити за допомогою функції:
int far getpalettesize (void);
При визначенні реального кольору пікселя на екрані значення його атрибуту використовується як індекс у таблиці кольорів дисплейного адаптера. Максимальне значення атрибуту пікселя, яку дозволяється використати для запису в відеопам'ять такими функціями, як графічні примітиви, повертається функцією
int far getmaxcolor (void);
Безпосереднє зміна внутрішньої палітри здійснюється за допомогою функцій setpalette або setallpalette. Перша змінює зміст тільки одного входу палітри, а друга всіх відразу. Синтаксис першої функції:
void far setpalette (int num_color_pallete, int num_color);
Аргумент num_color_palette задає номер змінюваного входу внутрішньої палітри і повинен лежати в межах від нуля до size-1 (size - елемент структури даних palettetype). Аргумент color задає нове значення коду кольору для цього входу в діапазоні від 0 до 63 (реально використовуються тільки шість молодших біт аргументу num_color).
Інша функція, що змінює внутрішню палітру, має синтаксис:
void far setallpalette (struct palettetype far * palette);
Аргумент її є покажчиком на структуру, що містить варіант бажаної палітри. Всі зміни в поточної внутрішньої палітрі, вироблені функціями setpalette і setallpalette негайно відображаються на екрані дисплея.
Кольором фону можна керувати за допомогою функції
void far setbkcolor (int num_color_palette);
Дія функції полягає в тому, що нульовий вхід внутрішнього палітри пов'язується зі входом, які мають номер num_color_palette. Це означає, що в нульовий елемент внутрішньої палітри записується значення, яке в даний момент міститься в елементі з номером num_color_palette. Крім того, всі наступні зміни вмісту елемента з номером num_color_palette будуть негайно дублюватися в нульовий елемент. Зауважимо, що функція setpalette (0, color) просто змінює колір фону, але не пов'язує нульової вхід ні з яким іншим.
Зворотної для функції установки кольору фону є функція
int far getbkcolor (void);
яка повертає поточне призначення для фонового кольору, тобто номер того входу внутрішньої палітри, з яким пов'язаний зараз нульовий вхід. Якщо раніше за допомогою функції setbkcolor не відбулося зв'язування ні з яким входом, то getbkcolor повертає 0.
Для отримання інформації про поточної внутрішньої палітрі існує дві функції:
void far getpalette (struct palettetype far * palette);
struct palettetype far * getdefaultpalette (void);
Перша копіює в область пам'яті, на яку вказує аргумент, поточний стан внутрішньої палітри. Інша повертає покажчик на що зберігається у графічній системі структуру, що містить еталон внутрішньої палітри. Отримавши покажчик на цю структуру, можна змінити сам еталон палітри. Такі зміни будуть зберігатися до наступного ініціалізації будь-якого режиму.
Всі вищеописані способи динамічного управління кольором розраховані на адаптери, в яких піксель може бути представлений не більше ніж чотирма бітами. Однак деякі адаптери допускають восьмибітових величину атрибуту пікселя (IBM8414 і VGA, що мають у таблиці кольорів 256 входів). Для них існує розширена палітра, яка містить 256 входів. Кожен вхід відповідає коду кольору. Для того щоб будь-якого коду відповідав інший відтінок кольору, використовується функція
void far setrgbpalette (int num_color, int red, int green, int blue);
Аргумент num_color - номер входу розширеної палітри (0-255), за яким зберігаються три колірні компоненти - червона, зелена і синя - складові бажаний колір. Функція дозволяє записати по входу розширеної палітри з номером color колірні компоненти red, green і blue. При цьому реально використовуються лише молодші шість байт кожної компоненти. Таким чином, загальна кількість колірних відтінків одно N_colors = 64 * 64 * 64 = 256К.
Відзначимо деякі особливості використання драйвера VGA. Значення елементів масиву colors (кодів квітів) звичайної внутрішньої палітри служать індексами для пошуку потрібного кольору у розширеній таблиці, звідки відбувається вибір потрібного відтінку кольору.
Зауважимо, що функція setrgbpalette правильно працює тільки з дисплейними адаптерами VGA і IBM8514. На інших конфігураціях ПК вона ігнорується. До речі, змінити палітру при роботі з адаптером IBM8514 можна тільки за допомогою функції setrgbpalette.
Розглянемо тепер поняття поточного значення малює кольору (current drawing color). Малює колір - це те значення, яке використовується функціями малювання для запису в атрибути пікселів. Значення малює кольору неотрицательно і не повинно перевищувати значення, що повертається функцією getmaxcolor.
Існує функція, що дозволяє явно змінювати поточне значення малює кольори:
void far setcolor (int num_color_palette);
При малюванні використовується колір, чий код записаний по входу внутрішньої палітри з номером num_color_palette. Дізнатися поточне значення малює кольору можна за допомогою функції
int far getcolor (void);

1.5. Базові функції доступу до відеопам'яті

Практично вся робота з графікою зводиться до обміну даними між програмою і відеобуфером дисплейного адаптера.
Доступ до окремих пікселям активної сторінки здійснюють дві функції:
unsigned far getpixel (int x, int y);
void far putpixel (int x, int y, int num_color_palette);
Функція getpixel повертає атрибут (вхід у внутрішню палітру) пікселя з координатами (x, y). А функція putpixel малює піксель в точці з координатами (x, y) кольором, чий код міститься по входу у внутрішню палітру з номером num_color_palette.
Незважаючи на те, що функцій getpixel і pupixel координати пікселя задаються в системі координат графічного вікна, ніщо не заважає вказати координати кожного пікселя сторінки, що лежить поза вікна. При цьому getpixel повертає правильне значення атрибуту зазначеного пікселя. Поведінка функції putpixel залежить від режиму відсікання, встановленого за допомогою останнього аргументу при виклику функції setviewport. Результати роботи функцій getpixel і pupixel з виходять за межі сторінки координатами точок непередбачувані.
Окрім обміну з відеопам'яттю окремими пікселями графічна бібліотека надає можливості для обміну цілими масивами пікселів. Це буває корисно, наприклад, коли потрібно тимчасово зберегти якийсь фрагмент сторінки, щоб надалі відновити його на колишньому або новому місці. Обмін проводиться прямокутними масивами, які задаються координатами своїх кутів у системі координат поточного графічного вікна.
Перш ніж зберегти фрагмент сторінки, необхідно визначити необхідний для цього обсяг оперативної пам'яті. Всі необхідні обчислення виробляє функція
unsigned far imagesize (int left, int top, int right, int bottom);
Вона отримує в якості аргументів координати лівого верхнього і правого нижнього кута зберігається області. Значення, що повертається можна передавати однією з функцій виділення пам'яті для резервування необхідного простору. Якщо обсяг пам'яті, необхідний для збереження зображення, перевершує 64К-1, то функція все одно повертає значення 0xFFFF, але при цьому graphresult видає значення -11.
Після резервування необхідного обсягу оперативної пам'яті, він може зберегти масив пікселів за допомогою функції
void far getimage (int left, int top, int right, int bottom, void far * bitmap);
Останній аргумент - покажчик на область пам'яті, де буде зберігатися масив.
Для того щоб масив пікселів, збережений за допомогою функції getimage, знову записати на активну сторінку, використовується функція
void far putimage (int left, int top, void far * bitmap, int op);
При цьому можна не тільки вказати нове місце розташування масиву пікселів (через координати лівого верхнього кута), але і вивести його на іншу сторінку відеопам'яті, попередньо зробивши її активної за допомогою функції setactivepage. Останній аргумент функції putimage вказує спосіб, яким атрибути пікселів масиву, виведеного з оперативної пам'яті на активну сторінку, будуть заміщати вже знаходяться в відеобуфері значення. У найпростішому випадку, коли op = 0, відбувається просте копіювання атрибутів пікселів з пам'яті в відеопам'ять. Однак можливе виконання однієї з побітових логічних операцій над вмістом оперативної пам'яті і відеобуфера для кожного пікселя масиву. Повний набір таких операцій задається перераховуваною типом putimage_ops:
enum putimage_ops
{COPY_PUT, XOR_PUT, OR_PUT, AND_PUT, NOT_PUT};
При роботі з функціями getimage і putimage діють приблизно ті ж правила щодо задаються координат, що і для функцій getpixel і putpixel: хоча координати задаються в системі графічного вікна, можна вказати масив пікселів, розташований в будь-якому місці в межах активної сторінки. Різниця між двома функціями полягає в тому, що getimage "схопить" цей масив, а функція putimage виведе масив на сторінку так, як якщо б ніякого графічного вікна не існувало (тобто ігнорується режим відсікання).
Якщо координати задається масиву пікселів (весь масив або його частину) виходять за межі сторінки, то результат роботи функцій getimage і putimage непередбачуваний.

1.6. Графічні примітиви

Основне значення графічних примітивів - забезпечити наявність програмних засобів для малювання всіляких геометричних об'єктів. Умовно можна розбити всі графічні примітиви за типом змальованих ними графічних об'єктів на дві групи: контурні і майданні. Функції першої групи малюють всілякі контурні лінії. До другої групи належать функції, призначені для малювання геометричних фігур з зафарбовуванням обмежуються ними областей.
До групи контурних графічних примітивів належать функції:
void far line (int x1, int y1, int x2, int y2);
void far linerel (int dx, int dy);
void far lineto (int x, int y);
void far rectangle (int left, int top, int right, intbottom);
void far drawpoly (int num_points, int far * poly_points);
void far circle (int x, int y, int radius);
void far arc (int x, int y, int start_angle, int end_angle, int radius);
void far ellipse (int x, int y, int start_angle, int end_angle, int x_radius, int y_radius);
Перші п'ять малюють кусково-лінійні об'єкти (у тому числі і фігури, складені з відрізків прямих), решта - криві другого порядку (дуги кіл і еліпсів).
Функції line, linerel і lineto з'єднують дві точки площини відрізком прямої. Для першої обидві сполучаються точки вказуються явно своїми координатами. Функції linerel і lineto в якості першої точки використовують поточну графічну позицію CP, а другу вибирають аналогічно функціям moverel і moveto, тобто через збільшення координат або за явною вказівкою. Всі три функції користуються системою координат графічного вікна. Проте їм можна передати координати будь-яких точок, навіть лежать за межами сторінки. Функція graphresult не повідомляє про помилку, а з'єднує лінія проводиться правильно. Якщо для вікна встановлено режим відсікання, то частини лінії, які виходять за межі вікна, не заносяться в відеопам'ять.
Функція rectangle малює на сторінці відеопам'яті контур прямокутника за вказаними координатами лівого верхнього і правого нижнього кута.
Функція drawpoly малює ламану лінію, з'єднуючи точки на площині. У першому аргументі передається кількість таких точок, а другий вказує на масив цілих чисел. Кожна пара чисел з цього масиву інтерпретується як пара координат (x, y) черговий точки. Для того щоб намалювати замкнуту ламану лінію (багатокутник), перша і остання пари елементів масиву повинні бути однаковими.
Функція circle малює коло радіусом radius з центром в точці з координатами (x, y). Функція arc і ellipse викреслюють дуги кола й еліпса з центром в точці (x, y), відповідно обмежені кутами start_angle і end_engle. Для дуги кола задається її радіус radius, а для дуги еліпса радіуси по осях x_radius і y_radius. Осі еліпса завжди передбачаються паралельними осям координат сторінки.
Кути, що обмежують дуги, виражаються в градусах і відміряються проти годинникової стрілки від напрямку, що задається віссю X сторінки. Дуга завжди проводиться від кута start_angle до кута end_angle також проти годинникової стрілки.
Для функцій rectangle, drawpoly, circle, arc і ellipse справедливі зауваження щодо системи координат і режиму відсікання, які були зроблені стосовно функцій малювання ліній.
З дугами кіл пов'язана функція
void far getarccoords (struct arccoordstype far * arccoords);
Ця функція повертає характеристики дуги кола, побудованої при останньому виклику функції arc. Характеристики дуги записуються в змінну * arccoords. Тип цієї змінної визначено наступним способом:
struct arccoordstype
{
int x, y;
int x_start, y_start, x_end, y_end;
};
Перша пара чисел - це координати центру кола, друга і третя - координати початку і кінця дуги. Значення координат прив'язані до системи координат графічного вікна.
Існують функції, які дозволяють варіювати зовнішній вигляд об'єктів, наприклад товщину і тип лінії, колір та інші.
Всі контурні графічні примітиви прописують пікселі у відеопам'яті малює кольором, який можна змінити функцією setcolor.
Для кусково-лінійних графічних примітивів, і тільки для них, є можливість вказати спосіб, яким код малює кольору буде взаємодіяти з атрибутами пікселів, вже перебувають у відеопам'яті на місці малюється об'єкта. Тут діє механізм, описаний для функції putimage. Вибір способу здійснюється функцією
void far setwritemode (int mode);
Аргумент цієї функції повинен приймати значення 0 (просте копіювання коду атрибуту пікселя в відеопам'ять) та 1 (операція "виключає або").
Функція
void far setlinestyle (int line_style, unsigned user_pattern, int thickness);
встановлює характер і товщину ліній геометричних об'єктів. Аргумент thickness впливає на контурні графічні примітиви, а аргументи line_style і user_pattern - тільки на кусково-лінійні.
Аргумент thickness приймає значення NORM_WIDTH (товщина дорівнює 1 піксель) і THICK_WIDTH (товщина дорівнює 3 пікселям). Аргумент linestyle задає характер рисуемой лінії. Значення аргументу повинні вибиратися з констант перечислимого типу line_styles (наприклад SOLID_LINE означає суцільну лінію):
enum line_styles
{
SOLID_LINE = 0, DOTTED_LINE, CENTER_LINE,
DASHED_LINE, USERBIT_LINE
};
Якщо значення аргументу line_style одно USERBIT_LINE, то це означає, що при побудові кусково-лінійних примітивів буде використовуватися шаблон, заданий програмістом і переданий функції setlinestyle за допомогою аргументу user_pattern. За допомогою шаблона можна задати періодично повторюваний малюнок лінії з періодом до 16 пікселів. Якщо певний біт шаблону user_pattern дорівнює 1, то відповідний піксель лінії малюється, в іншому випадку - ні.
Установки, зроблені за допомогою функції setlinestyle, зберігаються до нового її виклику. Для з'ясування поточної установки характеристик ліній передбачена функція
void far getlinesettingstype (struct linesettingstype far * line_info);
Ця функція заносить інформацію в структуру, що має опис
struct linesettingstype
{
int linestyle;
unsigned upattern;
int thickness;
}
Група майданних графічних функцій має прототипи:
void far bar (int left, int top, int right, int bottom);
void far bar3d (int left, int top, int right, int bottom, int depth, int top_flag);
void far fillpoly (int num_points, int far * poly_points);
void far fillellipse (int x, int y, int x_radius, int y_radius);
void far pieslice (int x, int y, int start_angle, int end_angle, int radius);
void far sector (int x, int y, int start_angle, int end_angle, int x_ radius, int y_radius);
void far floodfill (int x, int y, int num_color_palette);
Функції bar і bar3d будують прямокутники, координати яких задані першими чотирма аргументами функцій і зафарбовують його внутрішню область. Функція bar не виводить зовнішній контур прямокутника, а функція bar3d додатково обрамляє прямокутник контуру і тим же контуром домальовує проекцію паралелепіпеда, побудованого на базі цього прямокутника. Глибина проекції задається аргументом depth, аргумент top_flag вказує, малювати (якщо не нуль) або не малювати (якщо нуль) верхні ребра паралелепіпеда.
Функція fillpoly отримує аргументи аналогічно функції drawpoly, малює контур і заповнює його нутро. Однак якщо функція drawpoly допускає незамкнуті контури, то функція fillpoly завжди з'єднує останню крапку в отриманому списку з першою, автоматично замикаючи контур.
Функція fillellipse заповнює еліпс з центром в точці (x, y) і радіусами x_radius і y_radius. Крім того, вона малює контур еліпса.
Функції pieslice і sector схожі тим, що обидві зафарбовують зазначені сектора, тільки pieslice робить це для кругового сектора, а sector для еліптичного. Аргументи, які їм передаються, ті ж, що і для функцій arc і ellipse відповідно. Після того як сектор зафарбований, малюється його контур. На відміну від функцій arc і ellipse, функції pieslice і sector будують сектор від меншого значення кута до більшого (а не від start_angle до end_angle). Через це неможливо змусити функції pieslice і sector зобразити сектор, що перетинає позитивний напрямок осі X.
Функція floodfill використовується для зафарбовування областей, вже існуючих на сторінці. Для коректного функціонування необхідно, щоб контур був замкнутий і складався з пікселів, які мають значення атрибуту, що збігається з аргументом num_color_palette (номер входу внутрішньої палітри). Крім коду контуру, функція floodfill отримує точку, від якої починається заповнення області. Ця точка має знаходитися всередині контуру.
Всі контури у відеопам'яті прописуються пікселями малює кольору, який можна змінити функцією setcolor. Бажаний режим зображення контуру (наприклад товщина лінії) встановлюється так, як це робиться для контурних примітивів.
Для керування виглядом заповнення внутрішньої області служить функція
void far setfillstyle (int pattern, int num_color_palette);
Дана функція одночасно встановлює тип двовимірного шаблону заповнення та код заповнення (номер входу у внутрішню палітру). Потрібно відзначити, що при заповненні області немає можливості виконувати побітові логічні операції між кодами шаблону і атрибутами пікселів області, тобто завжди відбувається копіювання в атрибути пікселів області відповідних кодів шаблону. Аргумент pattern вказує на тип встановлюваного шаблону. Існує кілька заздалегідь визначених типів, їх символічні імена визначаються перераховуваною типом fill_patterns:
enum fill_pattern
{
EMPTY_FILL = 0, SOLID_FILL, LINE_FILL, LTSLASH_FILL,
SLASH_FILL, BKSLASH_FILL, LTBKSLASH_FILL,
HATCH_FILL, XHATCH_FILL, INTERLEAVE_FILL,
WIDE_DOT_FILL, CLOSE_DOT_FILL, USER_FILL
};
Аргумент pattern може приймати будь-які значення, крім USER_FILL. Значення цієї константи використовується тільки при обробці інформації, одержуваної функцією getfillsettings (див. далі).
Шаблон умовно можна представити у вигляді матриці розміром 8 х 8 елементів. Елементи матриці шаблону мають значення 0 або 1. Якщо елемент дорівнює 1, то атрибуту відповідного пікселя області буде присвоєно значення num_color_palette, у противному випадку атрибут пікселя отримає значення коду фону.
Можливе створення додаткових шаблонів безпосередньо в прикладній програмі. Для цього слід скористатися функцією
void far setfillpattern (char far * user_pattern, int num_color_palette);
Параметр user_pattern вказує на область, яка містить шаблон заповнення, описаний у програмі. Другий параметр цієї функції аналогічний такому ж параметру функції setfillstyle. Дана область складається з восьми послідовних байтів, ланцюжок бітів кожного байта є відповідним рядком матриці шаблону.
Майданні графічні примітиви використовують параметри заповнення, встановлені при останньому виклику функції функцій setfillstyle або setfillpatern. Для того щоб дізнатися про поточні призначення для параметрів заповнення областей, передбачені дві функції
void far getfillsettings (struct fillsettingstype far * fill_info);
void far getfillpattern (char far * user_pattern);
Перша повертає в область пам'яті за вказівником fill_info інформацію про поточний заповненні. Інформація заноситься в структуру наступного типу:
struct fillsettingstype
{
int pattern;
int color;
};
Елемент структури pattern вказує тип шаблону (якщо він дорівнює USER_FILL, то це означає, що шаблон заданий користувачем), елемент color містить код заповнення (номер входу у внутрішню палітру). Друга функція по переданому їй адресою записує матрицю шаблону, встановлену користувачем.

1.7. Висновок графічного тексту

Наступний набір функцій призначений для формування на сторінках відеопам'яті текстових повідомлень з використанням спеціальних шрифтів.
Щоб скористатися можливостями, наданими шрифтами в програмі, перш за все необхідно ініціалізувати знакогенератор графічної системи. Ініціалізацію графічного знакогенератора виконує функція settextstyle.
У Borland C передбачена робота в графічному режимі з двома принципово різними типами графічних шрифтів: матричними (bit-mapped) і векторними (stroked). Перший тип подається тільки одним шрифтом, спочатку вбудованим в BIOS комп'ютера. Шрифтів другого типу може бути декілька.
Набір символів матричного шрифту містить всі 256 допустимих ASCII-коду. Кожен символ шрифту представлений у вигляді матриці (бітової карти) розміром 8 х 8 пікселів. Так як цей набір символів вбудований в BIOS, то не потрібно завантаження ніякої додаткової інформації для його ініціалізації.
Інший принципово відмінний тип графічних шрифтів передбачає малювання символів тонкими лініями. Тому шрифти даного типу можна назвати векторними. Кожен символ представлений послідовністю керуючих кодів, які змушують генератор малювати відрізки прямих ліній, що з'єднують характеристичні точки символу. Таблиці символів векторних шрифтів поставляються в закодованому вигляді в спеціальних файлах шрифтів, що мають розширення. Chr. Далеко не всі векторні шрифти мають повний набір 256-ти кодів. Спільними для всіх шрифтів є символи з кодами від 32 до 126. Різні символи одного і того ж шрифту можуть мати різні розміри залежно від ширини конкретного символу.
Існує перераховувані тип font_names, що задає символічні імена для номерів п'яти графічних шрифтів (один матричний і чотири векторних з мінімального набору):
enum font_names
{
DEFAULT_FONT = 0, TRIPLEX_FONT, SMALL_FONT, SANS_SERIF_FONT, GOTHIC_FONT
};
Найбільш простим способом ініціалізації знакогенератора (завантаження певної таблиці символів) є автоматичне завантаження з використанням функції
void far settextstyle (int font, int directon, int charsize);
Функція встановлює основні параметри виведення графічних текстів (шрифт, напрям рядків і розмір символу). Ці параметри залишаються незмінними до наступного виклику функції settextstyle.
Перший параметр font задає номер ініціалізіруемого шрифту. Йому можна привласнити значення однієї з констант перечислимого типу font_names. Набір символів матричного шрифту вбудований в BIOS, і від функції не потрібно додаткових дій при його завантаженні. Для векторних шрифтів при автоматичній завантаженні проводиться пошук відповідного chr-файлу. Спочатку проглядається директорія, зазначена аргументом path_to_bgi функції initgraph, потім поточна директорія. Якщо файл шрифту не знайдений, встановлюється негативний код помилки. Знайдений chr-файл зчитується в автоматично виділяється область пам'яті. При неможливості виділити необхідну пам'ять також встановлюється відповідний код помилки. При виникненні будь-якої помилкової ситуації функція settextstyle виконується до кінця, але ініціалізує при цьому вбудований матричний шрифт замість заданого векторного шрифту.
Аргумент direction може приймати одне зі значень, певне константами HORIZ_DIR і VERT_DIR. Він задає напрямок рядка, що виводиться тексту: HORIZ_DIR визначає звичайний напрямок (горизонтальний рядок, символи йдуть зліва направо), VERT_DIR розгортає рядок на 90 градусів проти годинникової стрілки. Використання вертикального розташування рядка може призвести до зміни пропорцій символів, що виводяться - вони стають нижчими і ширше, ніж у горизонтальному рядку, що пов'язано з ефектом "неквадратні" пікселя в деяких дисплеях і ніяк непереборно.
Останній аргумент charsize управляє масштабом символів, що виводяться. Діапазон допустимих значень: від 1 до 10 для всіх графічних шрифтів і додаткове значення 0 тільки для векторних. Позитивне значення charsize вказує на однакове збільшення символів по обох осях. Якщо для векторних шрифтів задати charsize, рівний USER_CHAR_SIZE (визначена як 0), то при цьому визначаються два незалежних коефіцієнта масштабування - для ширини і висоти символу. За умовчанням в цьому режимі знакогенератор малює символи векторного шрифту в базовому варіанті згідно з описом з chr-файлу. Однак є можливість змінити масштаб за допомогою функції
void far setusercharsize (int mult_x, int div_x, int mult_y, int div_y);
Ця функція встановлює нові розміри символу, множачи ширину і висоту базового варіанту кожного символу на значення виразу ((double) mult_x / div_x) і ((double) mult_y / div_y) відповідно.
Головним недоліком автоматичної ініціалізації знакогенератора за допомогою функції settextstyle є те, що вона звертається до диску для читання chr-файлу під час виконання програми. Альтернативою автоматичної ініціалізації знакогенератора є статичне включення в програму таблиці символів векторних шрифтів. Для цього спочатку потрібно за допомогою утиліти bgiobj.exe перетворити chr-файли в об'єктні файли c розширенням. Obj. Потім їх можна включити в програму як звичайні об'єктні файли.
Перед статичної ініціалізацією знакогенератора необхідна реєстрація потрібної таблиці векторних шрифтів, для чого передбачена функція, якій потрібно передати місце розташування в оперативній пам'яті таблиці символів шрифту:
int registerbgifont (void (* font) (void));
В якості покажчиків використовуються імена, вже визначені в об'єктних файлах шрифтів. Нижче наведені описи тих імен, які потрібно вживати для шрифтів з мінімального набору:
void triplex_font (void);
void small_font (void);
void sansserif_font (void);
void gothic_font (void);
При успішній реєстрації шрифту значення, що повертається неотрицательно. Далі для ініціалізації знакогенератора використовується функція settextstyle з необхідними установками для шрифту. Тоді у присутності на диску chr-файлу відпадає всяка необхідність.
Графічна система дозволяє позиціонувати на сторінці відеопам'яті виведений текст з точністю до пікселя, для цього функцій виведення тексту потрібно деяку опорну точку. Розташуванням рядка, що виводиться щодо опорної точки управляє функція
void far settextjustify (int horiz, int vert);
Її аргументи можуть приймати значення констант перечислимого типу text_just:
enum text_just
{
LEFT_TEXT = 0, CENTER_TEXT, RIGHT_TEXT,
BOTTOM_TEXT, TOP_TEXT
};
У випадку помилки функція settextjustify встановлює код помилки, рівний -11, і зберігає попередній режим позиціонування.
Позиціонування горизонтальних рядків відбувається наступним чином. Якщо уявити прямокутник, в який вписано виводиться рядок, то пара аргументів horiz і vert описують положення опорної точки у прямокутнику.
При ініціалізації графічного режиму опорна точка всіх рядків розташовується в лівому верхньому кутку прямокутника, в який вписується горизонтальний рядок.
У позиціюванні вертикальних рядків є деякі особливості. Потрібно пам'ятати, що функція settextjustify управляє розміщенням щодо опорної точки саме прямокутника, що містить текст. З цього випливає, що по відношенню до самого тексту (оскільки він повернуть на 90 градусів) позиціонування праворуч і ліворуч від опорної точки визначається аргументом vert, а зверху чи знизу - аргументом horiz. Аргумент vert обробляється так само, як і для горизонтальної рядка. Аргумент horiz веде себе по-іншому. При значеннях LEFT_TEXT і RIGHT_TEXT він дає однаковий результат - текстовий прямокутник розташовується зліва від опорної точки.
У графічній бібліотеці існує функція, яка дає змогу отримати інформацію про поточний режим виведення графічних текстових повідомлень:
void far gettextsettings (struct textsettingstype far * texttypeinfo);
Інформація заноситься в область пам'яті, виділену в програмі і містить таку структуру:
struct textsettingstype
{
int font, direction, charsize;
int horiz, vert;
};
Для правильного розміщення тексту на сторінці необхідно знати розміри займаного їм простору, яке залежить від типу шрифту і його масштабування. Цю інформацію видають функції:
int far textheight (char far * text_string);
int far textwidth (char far * text_string);
Вони повертають висоту і ширину (в пікселях) прямокутника, в який був би вписаний текст при виведенні рядка text_string знакогенератора поточного шрифту з урахуванням встановленого в даний момент масштабу шрифту. Сам висновок тексту при цьому не проводиться.
При своїй роботі функції виведення тексту створюють у відеопам'яті малюнок символів рядка, використовуючи таблицю вибраного шрифту. Код, який при цьому заноситься в атрибути пікселів, тобто поточне значення малює кольору (номер входу у внутрішню палітру), яке встановлюється функцією setcolor. Ніяких бітових операцій з атрибутами пікселів відеопам'яті не передбачено. Лінії, якими малюються символи векторних шрифтів, завжди суцільні тонкі, вони не можуть модифікуватися функцією setlinestyle.
На відміну від текстового режиму, фон символів, що виводяться (колір прямокутника, в який вписано рядок) не змінюється. Якщо потрібно вивести рядок на якому-небудь тлі, то фон потрібно намалювати окремо, наприклад за допомогою функції bar. Іншою важливою відмінністю графічного режиму від текстового є відсутність режиму мигання символу. Можна імітувати процес мигання, керуючи внутрішньої палітрою за допомогою функції setpalette.
Функцій виведення тексту дві:
void far outtext (char far * text_string);
void far outtextxy (int x, int y, char far * text_string);
Обидві як аргумент отримують покажчик на виведену рядок символів. Відмінність між цими функціями полягає у виборі опорної точки при позиціонуванні повідомлення на сторінці. Функція outtext використовує для цього поточну графічну позицію. Функція outtextxy отримує координати опорної точки через аргументи x і y. Координати задаються в системі координат поточного графічного вікна. При установці режиму відсікання зображення за межами вікна обидві функції також забезпечують відсікання фрагментів тексту, що виходить за межі графічного вікна.

2. ПРИЙОМИ ПРОГРАМУВАННЯ ГРАФІЧНОГО РЕЖИМУ

2.1. Підключення графічної бібліотеки

Для підключення графічної бібліотеки можна використовувати один з двох прийомів. По-перше, включити в меню оболонки BC + +3.1 опцію Options-Linker-Libraries-Graphics library. По-друге, створити проект і включити в нього вихідні cpp-файли і бібліотеку LIB \ graphics.lib.
Графічний режим може не працювати в оболонці, якщо не вистачає місця в динамічній пам'яті. Слід збільшити її розмір у пункті Options-Debugger-Heap size.

2.2. Ініціалізація графічного режиму

Найпростішу ініціалізацію здійснює наступний код
# Include <graphics.h>
void main ()
{
int gd = DETECT, gm;
initgraph (& gd, & gm, "c: \ \ bc31 \ \ bgi");
/ / Працюємо в графічному режимі
putpixel (100, 200, WHITE);
/ / ... ... ....
If (! Getch ())
getch ();
closegraph ();
}

2.3. Включення драйвера і шрифтів в виконуваний файл

Для включення графічного драйвер egavga.bgi у виконуваний файл необхідно:
а) у командному рядку виконати
C: \ BC31 \ BGI \ bgiobj.exe egavga
і отримати файл egavga.obj;
б) створити проект в оболонці за допомогою команди меню Project-Open і включити в нього файл egavga.obj і вихідні cpp-файли;
в) потім у тексті програми записати код
registerbgidriver (EGAVGA_driver);
initgraph (& gd, & gm, "");
Для включення графічних шрифтів (файлів з розширенням chr) у виконуваний файл необхідно:
а) у командному рядку виконати
C: \ BC31 \ BGI \ bgiobj.exe goth
і отримати файл goth.obj;
б) створити проект в оболонці за допомогою команди меню Project-Open і включити в нього файл goth.obj і вихідні cpp-файли;
в) потім у тексті програми записати код
registerbgifont (GOTHIC_font);
initgraph (& gd, & gm, "c: \ \ borlandc \ \ bgi");
/ / ... ... ... ... ... ... ...
settextstyle (GOTHIC_FONT, HORIZ_DIR, 10);
outtext ("Hello");
/ / ... ... ... ... ... ... ...

2.4. Малювання геометричних фігур

а) Намалюємо червоне сонце
setcolor (RED);
circle (100, 100, 50); / / червоне коло
setfillstyle (SOLID_FILL, RED);
floodfill (100, 100, RED) / * малюємо червоний коло, вказуючи внутрішню точку області і колір контуру * /
б) Намалюємо в центрі екрану квадрат зі стороною a, повернений щодо центру C на кут j проти годинникової стрілки. Нехай З (x 0, y 0) - математичні координати точки. Тоді вершини неповернутого квадрата мають координати
(X 0 + (sqrt (2) / 2) · a · cos (p / 4 + p / 2 · k),
y 0 + (sqrt (2) / 2) · a · sin (p ​​/ 4 + p / 2 · k)), де k = 0, 1, 2, 3.
При повороті на кут j отримуємо математичні вершини
(F k, g k) = (x 0 + (sqrt (2) / 2) · a · cos (p / 4 + p / 2 · k + j),
y 0 + (sqrt (2) / 2) · a · sin (p ​​/ 4 + p / 2 · k + j)),
де k = 0, 1, 2, 3.
Відповідно до даних, наведених п.2.11, переводимо математичні координати (f k, g k) в координати пікселів (u k, v k). Потім визначаємо цілочисельний масив A координат вершин замкнутого многоуольніка
{U [0], v [0], u [1], v [1], u [2], v [2], u [3], v [3], u [0], v [0] }.

Тепер малюємо квадрат за допомогою однієї функції
drawpoly (5, A);

2.5. Виділення пам'яті під великі одномірні масиви

Елементами масивів можуть бути структури великого розміру. Якщо і розмір масиву значний, то виділити динамічну пам'ять під такий масив одним викликом функції malloc не можна. Прототип цієї функції
void * malloc (unsigntd int T);
Тому максимальний розмір блоку пам'яті, який вона виділяє, не перевершує 64К.
Пропонується емулювати одновимірний динамічний масив двовимірним динамічним масивом з використанням масиву
покажчиків.
Наприклад, виділимо пам'ять під long T = 50000l структур
struct comp {
float re, im;
};
Загальний розмір такого масиву дорівнює 50 000 * 8 = 400 000 байт. Виберемо розміри двовимірного масиву
int m = 1000; / / кількість стовпців вибираємо довільно
int n = (int) ((T - 1) / m) +1; / / кількість рядків, нумерація рядків
з нуля
В останній (m-1)-му рядку прямокутної динамічної матриці m 'n можуть міститися елементи, які не належать вихідного одновимірного масиву. Тому при переборі елементів масиву необхідна відповідна перевірка.
comp ** A = NULL;
A = (comp **) malloc (m * sizeof (comp *));
/ / Перевірка виділення пам'яті
for (int i = 0; i <m; i + +)
A [i] = (comp *) malloc (k * sizeof (comp));
/ / Перевірка виділення пам'яті
for (i = 0; i <m; i + +)
for (int j = 0; j <n; j + +)
if ((long) i * k + j <T) / / працюємо тільки з елементами
/ / Вихідного одновимірного масиву {
A [i] [j]. Re = 0;
A [i] [j]. Im = 0;
}
/ / Робота програми
/ / Звільнення пам'яті
for (i = 0; i <m; i + +)
free (A [i]);
free (A);

2.6. Висновок числової інформації

Для виведення форматованих даних використовується двоетапний алгоритм. Спочатку дані записуються в рядок або, як іноді кажуть, в пам'ять. Потім рядок виводиться на графічний екран.
Наприклад виведемо дійсне число з двома знаками після коми.
char buf [5];
float x = 3.1415;
sprintf (buf, "% 4.2", x);
outtextxy (100, 100, buf);
Цифра 4 в форматної рядку задає кількість байтів в пам'яті, які буде займати виведена форматованої інформація без обліку ознаки кінця рядка. Прийом використовується для запобігання виходу за діапазон масиву. Подібна помилка виникла б у разі
x = 13.1415.

2.7. Затримка екрану

Організація затримки екрану не залежить від вибору графічного або текстового режиму, і реалізується таким чином
if (! getch ())
getch ();
Даний код коректно обробляє два можливих випадку. По-перше, при натисканні звичайної клавіші. При цьому з клавіатури в буфер введення поміщається ненульовий ascii-код символу, відповідного самій клавіші. Тоді умова! Getch () помилково і другий getch () не викликається.
По-друге, при натисканні клавіші з розширеним кодом (наприклад, функціональні клавіші, стрілки) з клавіатури в буфер введення надходять два числа: нуль і scan-код цієї клавіші. Тоді умова! Getch () істинно, викликається другий getch (), який зчитує scan-код і тим самим очищає буфер.
Іншим способом затримки екрану є код
while (! getch ())
;
Відзначимо, що стандартним способом затримки (у підручниках і прикладах із довідок за функцією) є виклик функції
getch ();
Однак цей спосіб некоректно обробляє натискання клавіші з розширеним кодом. У даному випадку в буфері залишиться один непрочитаний символ, який буде зчитуватися при наступному введенні інформації.

2.8. Реакція програми на натиснення конкретної клавіші

У наступному фрагменті виходимо з циклу після натискання клавіші Escape
# Define ESC 27
while (1) {
if (kbhit ()) {
char c = getch ();
if (c == 0)
{
getch ();
continue;
}
else if (c == ESC)
break;
}
/ / Робота циклу
}

2.9. Організація введення числової інформації

У графічних додатках введення текстової і числовий інформації реалізується також в графічному режимі. Для цього не можна використовувати функцію scanf, так як вона передбачає текстовий режим.
Пропонується наступний алгоритм для введення всього позитивного числа. Дані прочитуються з клавіатури посимвольний, зберігаються в пам'яті і потім розпізнаються за допомогою функції sscanf форматованого введення з рядка. Рядок виводиться в графічному режимі посимвольно.
# Define ENTER 13
main () {
/ / Ініціалізація графічного режиму
char c, buf [2], * str = (char *) malloc (1);
int number;
str [0] = '\ 0';
buf [1] = '\ 0';
while ((c = getch ())! = ENTER) {
if (c <0 "| | c> '9 ')
continue;
buf [0] = c; / / введений символ оформляємо у вигляді рядка
outtext (buf); / / і виводимо на екран у графічному режимі
str = realloc (str, strlen (str) + 2);
str [strlen (str) + 1] = '\ 0';
str [strlen (str)] = c; / / запам'ятовуємо символ в пам'яті
}
sscanf (str, "% d", & number);
}

2.10. Перевірка виходу аргументу функції з ОДЗ

Перевірку виходу змінної x з області допустимих значень функції f (x) можна реалізувати в самому тілі функції. У разі виходу з ОДЗ функція зводить глобальний прапор, який перевіряється в зухвалому функції.
Наприклад,
int flag = 0; / / глобальний прапор
/ / Працюємо з функцією y = x 1 / 2
float f (float x) {
if (x <0) {
flag = 1;
return 0;
}
else {
flag = 0;
return sqrt (x);
}
}
void main () {
float x, y;
scanf ("% f", & x);
y = f (x);
if (flag == 1)
printf ("Вихід з ОДЗ.");
else
printf ("Немає виходу з ОДЗ. Продовжуємо обчислення");
}

2.11. Графічна та математична системи координат

Для малювання графіка функції програмістові зручніше використовувати математичну систему координат (МСК), розташовану по центру екрану. Графічні функції працюють у графічній системі координат (ГСК).
x
y
(0, 0)
y
(0, 0)
x


а б
Рис. 1. Системи координат: а - математична; б - графічна
Ініціалізіруем змінні.
int maxx = getmaxx (),
maxy = getmaxy (),
px = 30, / / ​​кількість пікселів в одній математичної одиниці по осі Ох
py = px * ((float) maxx / maxy); / / кількість пікселів в одній математичної одиниці по осі Оy.
Відповідність між двома системами координат представлено
нижче
Відповідність між МСК і ГСК
МСК
ГСК
(0, 0) ... ... ... ... ... ... ... ... ... ... ... ....
(Maxx / 2, maxy / 2)
(1, 0) ... ... ... ... ... ... ... ... ... ... ... ....
(Maxx / 2 + px, maxy / 2)
(0, 1) ... ... ... ... ... ... ... ... ... ... ... ....
(Maxx / 2, maxy / 2 - py)
(X, y) .... ... ... ... ... ... ... ... ... ... ... ....
(Maxx / 2 + x px, maxy / 2 - y py)
(X, f (x)) ... ... ... ... ... ... ... ... ... ... ....
(Maxx / 2 + x px, maxy / 2 - f (x) py)
Реалізуємо масштабування по осі координат Ох так, щоб графік функції y = f (x) на заданому відрізку [a, b] розміщувався по всій ширині екрану. Для цього знайдемо коефіцієнти u і v лінійного відображення g (x) = ux + v, при якому відрізок [a, b] переходить у відрізок [0, maxx]. Із системи лінійних рівнянь
ua + v = 0
ub + v = maxx
знаходимо u = maxx / (ba), v =-a maxx / (ba). Тоді точці (x, f (x)) буде відповідати піксель
((Maxx / (ba)) * x - a * maxx / (ba), maxy / 2 - f (x) * py)),
де px = maxx / (ba). Потім графік можна намалювати за допомогою циклу, в якому лічильник є речовій математичної змінної. Наприклад:
for (float x = a; x <= b; x + = (ba) / maxx)
putpixel ((maxx / (ba)) * x - a * maxx / (ba), maxy / 2 - f (x) * py));
Даний цикл при великих a і b може виявитися нескінченним. Це можливо у випадку, якщо крок циклу (ba) / maxx буде менше відстані між числом a і його найближчим сусідом праворуч для типу float.

2.12. Використання двох відеосторінок

Для малювання обертається зірки (див. завдання 3.4) краще використовувати дві відеосторінки.
int page = 0;
for (double f = 0; f <2 × M_PI-M_PI / 100; f + = M_PI / 50) {
otrisovka (X0, Y0, R1, r2, fi0 + f, COLOR) / * малюємо нову зірку на активній сторінці, яка за замовчуванням має нульовий номер * /
setvisualpage (page) / * показуємо зображення нової зірки * /
page = abs (page-1); / * міняємо номер сторінки з 0 на 1 або навпаки * /
setactivepage (page) / * міняємо активну сторінку * /
otrisovka (X0, Y0, R1, r2, fi0 + f-M_PI / 50, getbkcolor ()); / * стираємо стару зірку на активній сторінці * /
}

2.13. Малювання зображень в bmp-форматі

Для створення фону в задачі про снігопад можна використовувати 16-ти кольоровий bmp-файл, так як це усуває проблему самостійного малювання фонового зображення засобами мови C + +. Для завантаження зображення з файлу треба виконати дії:
1) з позиції 22 у файлі прочитати висоту малюнка;
2) обчислити ширину записаного зображення
ширина = (размер_файла - 118) / висота;
3) завантажити сам малюнок, починаючи з позиції 118, враховуючи, що в одному байті міститься 2 пікселя і те, що зображення у файлі записано порядково, причому перший рядок записана в кінець файлу, а остання - з позиції 118.
/ / Карта заміщення квітів для створення візуального ефекту
char map [] = {0,12,2,6,9,5,3,8,7,4,10,14,1,13,11,15};
int y0 = getmaxy ();
/ / Відкриваємо картинку
FILE * f = fopen (fon, "rb");
if (f == NULL)
return 2;
/ / Читаємо ширину картинки
fseek (f, 0, 2);
long l = ftell (f) -118;
fseek (f, 22, 0);
int w, h;
fread (& h, 2, 1, f);
w = int (l / h);
/ / Читаємо і малюємо картинку
fseek (f, 118, 0);
int x = 0;
int y = 0;
while (1) {
c = fgetc (f);
if (feof (f))
break;
ch = map [c/16];
cl = map [c% 16];
putpixel (2 * x +0, y0-y, ch);
putpixel (2 * x +1, y0-y, cl);
if (+ + x == w) {
x = 0;
y + +;
}
}
fclose (f);

2.14. Робота з мишею

Виклики BIOS використовують програмні переривання. BIOS має декілька різних переривань для різних цілей. Для роботи з мишею використовують переривання 0x33. Для доступу до цих перериваннях використовується функція Сі з прототипом у файлі <dos.h>
int int86 (int num, REGS * in, REGS * out);
де num - номер переривання. Об'єднання REGS має вигляд
union REGS {
struct WORDREGS x;
struct BYTEREGS y;
};
struct WORDREGS {
unsigned int ax, bx, cx, dx, si, di, cflags, flags;
};
struct BYTEREGS {
unsigned char al, ah, bl, bh, cl, ch, dl, dh;
};
/ / Визначимо глобальну змінну
REGS regs;
/ / Показати курсор
void showcursor (void) {
regs.x.ax = 0x01;
int86 (0x33, & regs, & regs);
}
/ / Заховати курсор
void hidecursor (void) {
regs.x.ax = 0x02;
int86 (0x33, & regs, & regs);
}
/ / Отримання статусу миші
void get_mouse_status (int & button, int & x, int & y) {
regs.x.ax = 0x03;
int86 (0x33, & regs, & regs);
button = regs.h.bl;
x = regs.x.cx;
y = regs.x.dx;
}
/ / Приклад використання миші
main () {
/ / Ініціалізація графічного режиму
int button, x, y;
char str [20];
showcursor ();
while (1) {
get_mouse_status (button, x, y);
if (x == 0 | | y == 0)
break;
sprintf (str, "% d% d", x, y);
outtext (30, 30, str);
}
hidecursor ();
}

3. ЗАВДАННЯ ДЛЯ ЛАБОРАТОРНОЇ РОБОТИ

3.1. Зоряне небо

На екрані в безперервному режимі малюються зірки (пікселі) у випадковому місці і випадковим кольором. Розподіл випадкових величин рівномірний. При накладенні нової зірки на іншу видиму зірку обидві стираються. Малювання припиняється натисканням клавіші Escape. Потім відбувається підрахунок числа видимих ​​зірок, і відсоток заповнення неба виводиться по центру графічного екрану з точністю до сотих часток відсотка. Використовувати готичний шрифт розміром 1 см.
Малювання зірок і їх підрахунок реалізувати у вигляді окремих функцій. Отримати відповідь для двох режимів VGAHI і VGALO.

3.2. Снігопад

З верхньої частини і з бічних сторін екрану в безперервному режимі падають білі сніжинки в формі одного пікселя. Вихід з програми після натискання клавіші Escape. Сніжинки пролітають екран і знову з'являються. Створити на екрані графічний фон у вигляді блакитного півмісяця, красивого тексту та ін Фон не містить білого кольору і не повинен перемальовувати.
Щільність снігопаду вводиться на початку програми в текстовому режимі. Максимальна кількість сніжинок дорівнює 50 000. Параметри сніжинки знаходяться в призначеній для користувача структурі даних. Для зберігання інформації про сніжинки слід використовувати двовимірний динамічний масив структур.
Зсуви сніжинок містять хаотичну складову по горизонталі й вертикалі. Організувати управління вітром за допомогою клавіш-стрілок.

3.3. Малювання графіка функції

Намалювати графік функції y = f (x) на відрізку [a, b]. Речові кордону інтервалу вводяться з клавіатури в графічному режимі з можливістю редагування. Графік необхідно масштабувати по ширині екрану так, щоб відрізок [a, b] повністю вписався в екран.
Функція f (x) задається вихідним кодом на мові Сі. Здійснити перевірку виходу змінної x з ОДЗ.

3.4. Обертання зірки

Написати функцію, яка малює правильну п'ятикутну кольорову зірку, з наступними параметрами:
· X, y - математичні координати центру;
· R, r - математичні радіуси внутрішньої і зовнішньої кіл;
· Fi - кут між віссю x і одним з великих променів зірки, в радіанах;
· Col - колір контуру зірки;
· Colfill - колір заливки.
Написати також програму, в якій обертається червона зірка в центрі екрану.

СПИСОК

1. Керніган Б. Мова програмування Сі / Б. Керніган, Д. Рітчі. М.: Фінанси і статистика, 1992. 272 с.
2. Керніган Б. Мова програмування Сі. Завдання за курсом Сі / Б. Керніган, Д. Рітчі. М.: Фінанси і статистика, 1985. 192 с.
3. Юркін А.Г. Задачник з програмування / О.Г. Юркін. СПб.: Пітер, 2002. 192 с.
4. Подбельський В.В. Програмування на мові Сі: навч. посібник / В.В. Подбельський, С.С. Фомін. М.: Фінанси і статистика, 2005. 600 с.
5. Трофімов С.П. Програмування в Сі. Організація вводу-виводу: метод. вказівки / С.П. Трофімов. Єкатеринбург: УГТУ, 1998. 20 с.
6. Трофімов С.П. Програмування в Сі. Динамічно розподіляється пам'ять: метод. вказівки / С.П. Трофімов. Єкатеринбург: МІДО, 1998. 14 с.
Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Лабораторна робота
165.7кб. | скачати


Схожі роботи:
Основні поняття математичного програмування Побудова моделі задачі лінійного програмування
Програмування мовою С з використанням обєктно-орієнтованого програмування
Програмування мовою С з використанням об єктно орієнтованого програмування
Програмування
Програмування
Програмування CMOS
Лінійне програмування 2
Цілочислове програмування
Введення в програмування
© Усі права захищені
написати до нас