Графические устройства



 

Прямоугольники

При рисовании прямоугольников можно преследовать две разные цели -закрашивание (заливка) прямоугольной области экрана выбранным цветом или рисование сторон (контура) прямоугольника. Первая задача является более обшей, поэтому сначала мы рассмотрим способы ее решения.

Полоса заданного цвета

Предположим, что ширина прямоугольника равна ширине рабочей области экрана (Horsize), а ее высота (толщина) составляет N точек. В примере 3.12 приведен текст подпрограммы, которая последовательно рисует заданное количество горизонтальных линий длиной Horsize, в результате чего получается полоса нужной высоты.

Перед вызовом подпрограммы надо установить окно видеопамяти, в котором находится левый верхний угол полосы, а его адрес в этом окне записать в регистр di. Количество строк в полосе указывается в регистре сх. Для рисования строк подходит любой вариант подпрограммы horiine, описанный в предыдущем разделе. В зависимости от того, какой из них вы выберете, код цвета указывается только в регистре ai, в обоих байтах регистра ах или в четырех байтах регистра еах.

Пример 3.12. Закрашивание прямоугольной полосы

stripe: PushReg <di,cx,Cur win> ; сохранение di, ex и Cur win
fillbar: push ex ; сохранение текущего значения сх
mov ex, horsize ; задание размера строки
call horline ; вывод очередной строки
pop ex ; восстановление счетчика строк
loop fillbar ; управление выводом строк
PopReg <Cur win,cx,di> ; восстановление Cur win, ex и di
call SetWin ; восстановление исходного окна
ret ; возврат из подпрограммы

Выполнение подпрограммы примера 3.12 начинается с сохранения в стеке содержимого регистров di, сх и переменной cur_win. Закрашивание производится в цикле, имеющем метку fillbar. Регистр сх используется в этом цикле в качестве счетчика. Кроме того, в нем передается размер строки для подпрограммы horline. Поэтому в начале цикла содержимое сх сохраняется в стеке и восстанавливается после возвращения из horline. Благодаря этому команда loop fillbar работает с той величиной, которая была указана в регистре сх при обращении к подпрограмме stripe.

После завершения цикла fillbar восстанавливаются сохраненные в стеке величины и исходное окно видеопамяти, для чего вызывается подпрограмма setwin. Последняя команда выполняет возврат из подпрограммы.

В рассмотренном примере ширина полосы равнялась ширине рабочей области экрана. В таком случае после записи последней точки текущей строки автоматически происходит переход к началу следующей строки, для этого не нужны никакие дополнительные действия подпрограммы. Если же ширина прямоугольной области меньше Horsize, то адрес начала следующей строки должна устанавливать подпрограмма.

Вычисление адресов строк

Первые точки строк прямоугольной области находятся в одном столбце, поэтому в режимах PPG адреса начала смежных строк различаются на величину Horsize (см. табл. 3.3). Следовательно, если адрес начала текущей строки увеличить на Horsize, то получится адрес начала следующей строки. Обсудим, как это проще всего сделать.

Наиболее очевидный способ — сохранять адрес начала текущей строки и в нужный момент увеличивать его на Horsize. Однако это не самый простой способ, и вот почему. Если при вычислении адреса начала следующей строки происходит переполнение, то надо установить новое окно видеопамяти. Но оно уже могло быть изменено при рисовании текущей строки и повторное изменение недопустимо. Поэтому, прежде чем устанавливать новое окно, надо проверить, не изменилось ли оно при рисовании строки. Таким образом, простой на первый взгляд способ коррекции адреса плох тем, что неизвестно, какому окну видеопамяти соответствует сохраненный адрес и нужны дополнительные проверки для выяснения этого обстоятельства.

Лишние проверки можно исключить, если изменить способ коррекции так, чтобы использовалось текущее значение адреса, которое заведомо соответствует установленному окну видеопамяти. После вывода последней точки строки текущий адрес больше адреса ее первой точки на ширину прямоугольной области.

Следовательно, прибавив к нему значение переменной Horsize, уменьшенное на ширину прямоугольной области, мы получим адрес начала следующей строки. Если при сложении происходит переполнение, то устанавливается следующее окно видеопамяти без проверки каких-либо дополнительных условий. Мы будем использовать такой способ вычислений при построении прямоугольных рисунков различного назначения.

Закрашивание прямоугольной области. В примере 3.13 приведена подпрограмма, закрашивающая заданным цветом прямоугольную область произвольного размера. Перед ее вызовом адрес левого верхнего угла прямоугольника помещается в регистр di и устанавливается окно видеопамяти, которому принадлежит этот адрес. Ширина прямоугольника (количество точек в строке) помещается в регистр dx, а высота (количество строк или точек по вертикати) — в регистр сх. Задание кода цвета точек зависит от того, какой вариант подпрограммы horiine вы будете использовать. Horiine может записывать в видеопамять байты, слова или двойные слова (см. раздел). Соответственно один и тот же код цвета указывается в регистре ai, в обоих байтах регистра ах или в четырех байтах регистра еах.

Пример 3.13. Подпрограмма закрашивания прямоугольной области

rctngl: PushReg <bx, ex, di, Cur win> сохранение в стеке
mov bx, horsize копируем horsize в регистр bx
sub bx, dx и вычитаем ширину прямоугольника
filler: push ex сохранение счетчика повторов
mov ex, dx задание размера строки
call horline рисуем линию
pop ex восстановление счетчика повторов
add di, bx адрес начала следующей строки
jnc @F -> адрес в пределах окна
call NxtWin переход к следующему окну
@@: loop fillar управление повторами цикла
PopReg <Cur win,di, cx,bx> восстановление из стека
call setwin восстановление исходного окна
ret
возврат из подпрограммы

Выполнение примера 3.13 начинается с сохранения в стеке содержимого используемых регистров и переменной cur_win. После этого с помощью двух команд в регистре bx формируется константа для коррекции адресов строк. Как говорилось выше, она равна разности между значением переменной Horsize и шириной прямоугольника, указанной в dx перед вызовом подпрограммы.

Закрашивание прямоугольной области производится в цикле, имеющем метку filiar. Он отличается от аналогичного цикла filibar примера 3.12 тем, что после рисования каждой строки производится коррекция текущего адреса (команда add di, bx). Если при сложении не происходит переполнение результата, то новое значение адреса находится в пределах сегмента и команда jnc @F исключает вызов процедуры Nxtwin. В случае переполнения условный переход не выполняется и происходит установка следующего окна.

После выхода из цикла filiar, перед возвратом в вызывающий модуль, восстанавливаются сохраненные в стеке величины и исходное окно видеопамяти.

Рисование контура прямоугольника. Контур прямоугольника состоит из двух горизонтальных и двух вертикальных линий, поэтому для его рисования понадобятся подпрограммы horiine и anyline, описанные в предыдущем разделе. Прежде чем рассматривать подпрограмму, обсудим, как можно нарисовать контур прямоугольника с минимальными затратами на вычисление адресов начала его граней (сторон).

Будем считать, что опорной точкой является верхний левый угол контура, адрес которого известен. Если грани прямоугольника рисовать, например, в таком порядке — верхняя, правая, нижняя, левая, то вычислять адреса начала граней вообще не потребуется. Однако в таком случае понадобятся не две, а четыре подпрограммы. При рисовании верхней и правой граней адреса видеопамяти будут изменяться в естественном порядке в сторону их увеличения и можно использовать подпрограммы horiine и anyline. При рисовании же нижней и левой граней адреса видеопамяти будут изменяться в сторону их уменьшения и понадобятся еще две подпрограммы, рисующие линии в обратном направлении. Чтобы ограничиться двумя подпрограммами, изменим последовательность рисования граней.

Сначала рисуем верхнюю и правую грани, затем возвращаемся в левый верхний угол контура прямоугольника и рисуем левую и нижнюю грани. Можно сначала нарисовать левую и нижнюю грани, а затем верхнюю и правую. В обоих случаях при рисовании граней адреса видеопамяти изменяются в сторону их увеличения.

В примере 3.14 приведена подпрограмма, рисующая сначала верхнюю и правую, а затем левую и нижнюю грани. Входные параметры для нее совпадают с параметрами подпрограммы примера 3.13.

Пример 3.14. Подпрограмма рисования контура прямоугольника

round: PushReg <bx,Cur win,cx,di> ; сохранение исходного состояния
mov ex , dx ; ex = ширина прямоугольника
dec ex


 
Назад Начало Вперед