===== Графика в Паскале =====
Пример работы с графикой в нашей системе.
uses oglgraph; // Необходимая библиотека, у нас заменяет graph
var
gd, gm: smallint; // Имена не важны, а тип переменных - важен
begin
gd := Detect; // Автоматическая установка разрешения
gm := DetectMode;
initgraph(gd, gm, ''); // Открытие "графического окна"
{далее все, что Вы хотите нарисовать, например:}
setcolor(green);
line(0, 0, 100, 100);
{конец отрисовки}
repeat until graphkeypressed; // Задержка закрытия графического окна до нажатия
// клавиши для завершения работы программы -
// иначе рискуете ничего толком не увидеть
closegraph(); // закрытие графического окна - не обязательно, но рекомендуемо.
end.
Mx := GetMaxX div 2;
My := GetMaxY div 2;
for y := -my to my do
for x := -mx to mx do
begin
n := 0;
c.x := x * 0.005;
c.y := y * 0.005;
z.x := 0;
z.y := 0;
while (sqr(z.x) + sqr(z.y) < max) and (n < iter) do
begin
t := z;
z.x := sqr(t.x) - sqr(t.y) + c.x;
z.y := 2 * t.x * t.y+ c.y;
Inc(n);
if KeyPressed then
Cancel := true;
end;
if n < iter then
begin
PutPixel(mx + x,my + y,16 - (n mod 16));
end;
if Cancel then
exit;
end;
==== Примеры ====
Среди примеров - часто возникающие задачи.
uses oglgraph; { Подключаем нашу библиотеку }
var
gd, gm: smallint;
maxx, maxy : integer;
begin
gd := Detect;
gm := DetectMode;
initgraph(gd, gm, '');
maxx := getmaxx(); { Выясняем ширину экрана}
maxy := getmaxy(); { Выясняем высоту экрана}
{Внимание! Функции getmaxx и getmaxy правильно работают только после вызова initgraph }
setcolor(blue); { устанавливаем синий цвет для рисования линий }
rectangle(1, 1, maxx - 1, maxy - 1); { Рисуем прямоугольник с отступом в 1 пиксель от края экрана}
repeat until graphkeypressed; { Сохраняем рисунок на экране до нажатия кнопки}
closegraph();
end.
uses oglgraph;
var
gd, gm: smallint;
color : integer;
begin
gd := Detect;
gm := DetectMode;
initgraph(gd, gm, '');
color := white; {выбираем цвет с помощью описанной в библиотеке константы white}
setBkColor(color); {устанавливаем "нужный" цвет фона - ничего не происходит}
cleardevice; {"очищаем" экран нужным цветом - установленным цветом фона }
... {Можно что-то рисовать}
repeat until graphkeypressed; { Сохраняем рисунок на экране до нажатия кнопки}
closegraph();
end.
Другой способ
...
initgraph(gd, gm, '');
color := white; {выбираем цвет с помощью описанной в библиотеке константы white}
setfillstyle(1, color); {устанавливаем "нужный" цвет и способ "штриховки" при заливке - ничего не происходит}
floodfill(0,0,red); {"заливаем" экран нужным цветом - установленным цветом заливки,
пока не наткнёмся на красный, которого нет }
... {Можно что-то рисовать}
==== Процедуры и функции ====
^ Имя ^ Описание ^
|getmaxX()
|Функция, которая определяет максимальную ширину экрана в пикселях|
|getMaxY()
|Функция, которая определяет максимальную высоту экрана в пикселях|
|getX()
|Функция, которая определяет текущее положение невидимого графического курсора по оси X|
|getY()
|Функция, которая определяет текущее положение невидимого графического курсора по оси Y|
|moveTo(x, y)
|Перемещает графический курсор к пикселю с координатами (x,y)|
|moveRel(dx, dy)
|Смещает графический курсор на dx и dy пикселей по осям X и Y, соответственно|
| | |
|setColor(color)
|Устанавливает цвет для линий (line, arc и т.д.) и замкнутых контуров (circle и т.д.)|
|setLineStyle(LineStyle, Pattern, Thickness)
|Устанавливает тип и толщину линий (line, rectangle, circle и т.д.).|
| | |
|setBkColor(color)
|Устанавливает цвет фона|
|cleardevice
|Очищает экран, заливая его установленным цветом фона|
|setFillStyle(pattern, color)
|Устанавливает тип и цвет заливки плошадей (bar, floodFill и т.д.)|
| | |
|putPixel(x, y, color)
|Меняет цвет пикселя с координатами (x,y) на цвет, указанный параметром //color//|
|getPixel(x, y)
|Функция, которая определяет текущий цвет пикселя c координатами x и y|
| | |
|line(x1, y1, x2, y2)
|Рисует прямую линию из точки (x1,y1) в точку (x2,y2)|
|lineTo(x, y)
|Рисует прямую линию из текущей позиции в точку (x,y), перемещая графический курсор|
|lineRel(dx, dy)
|Рисует прямую линию из текущей позиции в позицию со сдвигом //dx//, //dy//, перемещая графический курсор|
| | |
|drawPoly(n, var An)
|Рисует ломаную линию из n точек с координатами, взятыми попарно из массива An, размерностью 2*n*sizeof(integer)|
| | |
|circle(centerX, centerY, radius)
|Рисует окружность (линию) с центром (x,y) и с радиусом r |
|arc(centerX, centerY, angle1, angle2, radius)
|Рисует дугу с центром (centerX, centerY) и радиусом r от угла angle1 до угла angle2, указанными в градусах|
|ellipse(centerX, centerY, angle1, angle2, radiusX, radiusY)
|Рисует эллипс с центром в (//centerX//, //centerY//) от угла angle1 до угла angle2, указанными в градусах, и с радиусами //radiusX//, //radiusY// |
|rectangle(x1, y1, x2, y2)
|Рисует незаполненный прямоугольник (прямоугольный контур) с координатами левого верхнего угла - (x1,y1) и правого нижнего угла - (x2, y2)|
| | |
|bar(x1, y1, x2, y2)
|Рисует заполненный прямоугольник (без граничной линии) с координатами левого верхнего угла --- (x1,y1) и правого нижнего угла --- (x2, y2)|
|bar3D(x1, y1, x2, y2, l, b)
|Рисует параллелепипед с прямоугольной боковой стенкой, заданной противоположными углами (x1, y1) и (x2, y2), и толщиной l. Параметр b указывает, рисовать ли верхнюю грань|
|fillEllipse(centerX, centerY, radiusX, radiusY)
|Рисует заполненный эллипс|
|fillPoly(n, an)
|Рисует заполненный многоугольник|
|pieSlice(centerX, centerY, angle1, angle2, radius)
|Рисует сектор круга|
|sector(centerX, centerY, angle1, angle2, radiusX, radiusY)
|Рисует сектор эллипса|
| | |
|floodFill(x, y, color)
|Определяет и заливает область, ограниченную контуром цвета //сolor// и краями экрана. Точка //(x,y)// должна находиться внутри контура. Внимание! Рисует очень медленно!|
==== Типы линий ====
^ Имя ^ Описание ^
|SolidLn| Сплошная линия |
|DottedLn| Пунктирная линия |
|CenterLn| |
|DashedLn| |
|UserBitLn| Пользовательский тип. Требуется задать параметр Pattern в процедуре setLineStyle значением от 0 до 65535 |
==== Толщина линий ====
^ Имя ^ Значение ^Описание ^
|NormWidth| 1 |Обычная линия |
|ThickWidth| 3 | Жирная линия |
Обратите внимание, что значение параметра **не задает толщину** линии, а указывает режим рисования. Написать ''setLineStyle(LineStyle, Pattern, **4**);'', вообще говоря, ошибка!
==== Стили заливки ====
^ Имя ^ Значения ^ Описание ^
|EmptyFill| 0 | |
|SolidFill| 1 | Сплошная заливка |
|LineFill| 2 | |
|LtSlashFill| 3 | |
|SlashFill| 4 | |
|BkSlashFill| 5 | |
|LtBkSlashFill| 6 | |
|HatchFill| 7 | |
|XHatchFill| 8 | |
|InterleaveFill| 9 | |
|WideDotFill| 10 | |
|CloseDotFill| 11 | |
==== Немигающий экран ====
Чтобы избежать мигания экрана при перерисовке "заполненных" объектов, применяется //метод двойной буферизации//. При этом используются два виртуальных экрана, один из которых виден, а другой в это время - перерисовывается. Затем он показывается на экране, а видимый ранее - убирается и перерисовывается.
В начале рисования **один раз** командой ''SetDoubleBuffer(true)'' вызывается двойная буферизация, затем, после прорисовки **каждого** нового кадра, производится обмен вновь перерисованого кадра с тем, который был показан на экране, командой ''graphSwapBuffers''.
Отключается войная буферизация командой ''SetDoubleBuffer(false)'';
==== Установка произвольного разрешения ====
m640x200x16 = VGALo;
m640x400x16 = VGAMed;
m640x480x16 = VGAHi;
{ VESA Specific video modes. }
m320x200x32k = $10D;
m320x200x64k = $10E;
m640x400x256 = $100;
m640x480x256 = $101;
m640x480x32k = $110;
m640x480x64k = $111;
m800x600x16 = $102;
m800x600x256 = $103;
m800x600x32k = $113;
m800x600x64k = $114;
m1024x768x16 = $104;
m1024x768x256 = $105;
m1024x768x32k = $116;
m1024x768x64k = $117;
m1280x1024x16 = $106;
m1280x1024x256 = $107;
m1280x1024x32k = $119;
m1280x1024x64k = $11A;
==== Работа с клавиатурой ====
В графическом режиме обработка событий клавиатура происходит очень похоже на текстовый режим, так как реализованы аналоги функций readkey и keypressed из модуля crt. В модуле oglgraph они называются graphreadkey и graphkeypressed. Функция graphkeypressed служит для определения события нажатия на клавиатуру, это логическая функция, которая возвращает два значения: истина или ложь. Обычно результатом ее работы будет всегда false, кроме того случая если нажата какая-нибудь клавиша на клавиатуре. В примерах выше это ее поведение используется для остановки выполнения программы перед закрытием графического режима:
repeat until graphkeypressed;
Когда выполнение программы доходит до приведенной строки, запускается цикл repeat-until, который работает до тех пор, пока условие не станет истинным, что в нашем случае произойдет только при нажатии любой клавиши.
Функция graphreadkey так же реагирует на нажатия, но в результате работы возвращает скан-код клавиши, т.е. уникальное целочисленное значение, которое соответствует коду клавиши, генерируемому контроллером клавиатуры.
code := graphreadkey;
Особенностью это функции является то, что она блокирует исполнение программы до того момента пока не будет нажата клавиша. Если же требуется реализовать работу с клавиатурой, которая бы не останавливала работу программы, то в этом случае нужно предварительно сделать проверку на нажатие клавиши с помощью graphkeypressed:
if graphkeypressed then
code := graphreadkey;
Напишем программу, которая опрашивает клавиатуру и выводит на экран коды клавиш:
uses oglgraph;
var
gd, gm, code: smallint;
begin
gd := Detect;
gm := DetectMode;
initgraph(gd, gm, '');
while true do
begin
if graphkeypressed then
begin
code := graphreadkey;
writeln(code);
end;
end;
closegraph;
end.
==== Примечания ====
Все параметры графических процедур и функций --- целые числа.
Ось Y направлена вниз. Следовательно, координаты левого верхнего угла - (0, 0).
Все процедуры и функции можно разбить на три группы.
Функции и процедуры, позволяющие узнать текущие настройки, начинаются с "get..." (getcolor и др.).
Процедуры, устанавливающие параметры рисования --- с "set..." (setcolor и др.).
Процедуры, осуществляющие рисование и все остальные, называются кто во что горазд, но более или менее осмысленно (circle, floodfill ...). "Рисующие" процедуры пользуются ранее установленными настройками или настройками по умолчанию. При изменении настроек, ранее сделанные рисунки не меняются.