ПОИСК
Категории книг
ОПРОС
Вопрос: Какой язык программирования вы предпочитаете
С/C++
Delphi
Visual Basic
Perl
Java
PHP
ASP
Другой
ЭТО ПОЛЕЗНО!
ОБРАТНАЯ СВЯЗЬ

/ Главная / Программирование / Иллюстрированный самоучитель по SVGA
Иллюстрированный самоучитель по SVGA

 

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

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

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

Предположим, что ширина прямоугольника равна ширине рабочей области экрана (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
уменьшаем ширину на 1
call horline
рисуем верхнюю грань
mov bx, horsize
bx = horsize
pop ex
восстанавливаем содержимое сх
push ex
и сохраняем его в стеке
call anyline
рисуем правую грань
PopReg <di,cx,Cur win>
восстанавливаем исходное состояние
PushReg <Cur win,cx,di >
и вновь запоминаем его
call SetWin
устанавливаем исходное окно
dec ex
уменьшаем высоту на 1
call anyline
рисуем левую грань
mov ex , dx
сх = ширина прямоугольника
call horline
рисуем нижнюю грань
PopReg <di,cx,Cur win,bx >
восстановление исходного состояния
call SetWin
восстановление исходного окна
ret
возврат из подпрограммы

Выполнение примера 3.14 начинается с сохранения в стеке переменной cur_win и регистров bx, сх и di. При вызове подпрограммы переменная Cur_win и регистр di задают адрес левого верхнего угла контура прямоугольника, а в регистре сх указывается высота прямоугольника (количество точек по вертикали).

При рисовании верхней грани ее размер сокращается на 1 точку, для того чтобы при возврате из подпрограммы horline в регистре di находился адрес первой точки правой грани. Правую грань рисует подпрограмма anyline, поэтому в регистр bx надо записать значение Horsize, а из стека восстановить и тут же снова сохранить в нем содержимое регистра сх. После возврата из подпрограммы anyline будут нарисованы верхняя и правая грани.

Теперь надо вернуться в левый верхний угол контура прямоугольника, восстановив исходное состояние, сохраненное в стеке, и заново сохранить его для использования при выходе их подпрограммы. Кроме того, восстанавливается исходное окно (команда call setwin), поскольку оно могло измениться при рисовании.

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

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

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

 


Компьютерные книги © 2006-2013
computers.plib.ru