Линии, строки и прямоугольные области. Подпрограммы для рисования линий.
Ускорение цикла рисования
В примере 7.5 после каждой переадресации выполняется проверка принадлежности нового значения адреса текущему сегменту и, в случае необходимости, устанавливается следующее окно видеопамяти. Вероятность того, что новое значение адреса выйдет за границу сегмента, достаточно мала. Например, при установке видеорежимов 110h или 111h (Hi-color, 640x480) рабочее пространство видеопамяти занимает 9 неполных окон. Если создаваемое изображение заполняет все это пространство, то только в восьми случаях из 307 200 возникнет необходимость изменения окна, а в остальных случаях проверка адресов не требуется. Сказанное не означает, что она вообще не нужна. Для сокращения количества дополнительных действий надо изменить способ проверки.
Один из вариантов сокращения бесполезных действий заключается в том, чтобы перед началом рисования лиж-ши проверять, помещается она в текущем сегменте или выходит за его пределы. Это исключает необходимость контроля адресов в цикле рисования. Если линия целиком расположена в одном сегменте, то цикл рисования выполняется один раз. В противном случае после рисования части линии, расположенной в текущем окне, устанавливается следующее окно и повторяется цикл рисования остатка линии.
Замечание
Рисование линии по частям в режимах PPG уже описано ранее, а соответствующая подпрограмма приведена в примере 3.8.
Подпрограмма Twopart
Нас интересует не простое рисование, а возможность ускорения выполнения различных действий с точками, расположенными на прямой линии. Поэтому текст примера 7.6 является своеобразным управляющим алгоритмом, который для выполнения конкретных действий вызывает вспомогательную подпрограмм у baseip. В данном примере она рисует прямую линию.
Входные параметры подпрограммы Twopart полностью соответствуют параметрам подпрограммы horiine (пример 7.5) и расположены в тех же регистрах.
Пример 7.6. Рисование линии по част-ям в режимах Hi-Color.
push dx coxp аняем содержимое регистра dx mov dx, di копируем адрес в регистр dx shl ex, 01!! для True Color – shl ex, 02 add dx, ex сумма исходного адреса и размера линии jc @F › прямая расположена в двух окнах xor dx, dx очис тка регистра dx @@: sub ex, dx количество точек в текущем окне shr сх, 01!! для True Color – shr ex, 02 call baseip рисуем всю линию или ее первую часть or di, di адрес в пределах текущего окна? jne hrl_exit › да, линия нарисована полностью call NxtWin установка следующего окна add ex, dx количество не нарисованных точек je hrl_exit линия нарисована полностью shr ex, 01!! для True Color – shr ex, 02 call baselp рисуем остаток линии hrl exit: pop dx восстановление содержимого dx ret возврат из подпрограммы ; Подпрограмма, выполняющая основные действия baselp: mov es: [di],ax!! для True Color – mov es: [di], eax. add di, bytppnt переадресация операнда loop baselp управление повторами цикла ret возврат из подпрограммы
Выполнение примера 7.6 начинается с сохранения в стеке содержимого регистра dx, поскольку оно изменяется в подпрограмме. При входе регистр сх содержит количество рисуемых точек, его надо преобразовать в количество байтов, с помощью сдвига и сложить с исходным адресом видеопамяти (в регистре dx). Если при этом происходит переполнение, то линия не помешается в текущем окне и ее надо рисовать по частям. В противном случае регистр dx очищается. После этого вычисляется количество точек в первой части и вызывается подпрограмма baselp, рисующая начало линии.
При первом вызове baselp может быть нарисована вся линия или только ее первая часть. Это важно знать для выполнения дальнейших действий. Они начинаются с проверки значения адреса, находящегося в регистре di.
Возможен случай, когда при первом рисовании достигнута граница окна. В таком случае в регистре di находится 0, но нулевой адрес принадлежит не текущему, а следующему окну видеопамяти. Поэтому если регистр di очищен, то обязательно надо сменить окно видеопамяти. Если же содержимое di отлично от нуля, то нарисована вся линия.
После установки окна суммируется содержимое регистров сх и dx. Если сумма равна нулю, то линия нарисована целиком, а код ее последней точки был записан в последнее слово сегмента. В противном случае количество байтов, полученное в регистре сх, преобразуется в количество точек и повторно вызывается подпрограмма baselp. Перед возвратом на вызывающий модуль восстанавливается исходное содержимое регистра dx, соответствующая команда имеет метку hri_exit.
Замечание
Практическая ценность примера 7.6 заключается в том, что он иллюстрирует способ обработки строки графического объекта по частям. Основные действия локализованы в подпрограмме baselp. Ее можно изменить так, чтобы вместо записи в видеопамять содержимого регистра ах выполнялись другие действия, например инверсия кодов точек, пересылка кодов из видеопамяти в оперативную или наоборот и т. д.