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

Построение геометрических фигур. Прямые линии.

Рисование линии справа налево

Рассмотрим, как можно нарисовать на экране горизонтальную прямую линию в направлении справа налево. Два варианта подпрограмм приведены в примере 3.7, их вызов отличается от вызова подпрограмм примера 3.6 только тем, что исходное окно видеопамяти и адрес в регистре di соответствуют крайней правой точке прямой.

Пример 3.7. Рисование горизонтальной линии справа налево.

; Вариант 1, используется команда пересылки .invline:mov es:[di],
 al запись кода точки в видеобуфер sub di, 01 уменьшение адреса на 1
jnc @F переход, если нет переноса
call PrevWin установка предыдущего окна
@@: loop invline управление повторами цикла
возврат из подпрограммы
Вариант 2, используется строковая операция.
 установка флага направления запись кода точки в видеобуфер начало нового сегмента? › нет

установка предыдущего окна управление повторами цикла
 очистка флага направления возврат из подпрограммы
invline: std
invlp: stosb
cmp di, – 1 jne @F call PrevWin
@@: loop invlp
eld ret

В примере 3.7 после записи в видеопамять содержимое регистра di уменьшается на 1, поэтому каждая следующая точка располагается на экране слева от предыдущей. Если при очередном уменьшении адреса будет пройдена нижняя граница сегмента, то надо установить предыдущее окно видеопамяти. Нижней границей текущего сегмента является нулевой адрес. При его уменьшении на 1 получается отрицательный результат, имеющий код OFFFFh, который является старшим адресом предыдущего сегмента.

Контроль текущего адреса выполняется по-разному. В первом варианте для этого проверяется состояние С-разряда регистра флагов после операции вычитания. При вычитании единицы из нуля он будет установлен, что приведет к вызову подпрограммы Prevwin. Во втором варианте вычитание выполняет строковая операция, не вырабатывающая признаки, поэтому проверяется код результата и если он равен ' -1", то вызывается подпрограмма FrevWIN.

Важно
В первом варианте примера 3.7 вместо команды sub di, 01 нельзя использовать dec di, поскольку последняя не вырабатывает признак переноса
.

Подпрограммы примера 3.6 достаточно просты, но это не самый быстрый способ рисования горизонтальной линии. Если не происходит смена окна, то при записи кода каждой точки выполняются четыре команды. В первом варианте одна из них (jne @F), а во втором две (or di, d i и jne @F) производят проверку текущих значений адреса.

Вероятность того, что при рисовании горизонтальной линии значение адреса выйдет за границу сегмента не превышает 1%. Например, при работе в режиме ioih точки только 4 из 480 строк расположены в двух окнах. Следовательно, примерно в 99% случаев проверка текущего адреса в процессе рисования не нужна, и выполняющие ее команды можно исключить из тела цикла записи точек. Сказанное не означает, что проверка не нужна вообще, просто она должна выполняться перед циклом рисования, а не в самом цикле.

Ускорение цикла рисования

Если из подпрограмм примера 3.6 исключить проверку адресов и установку следующего окна, то цикл записи в первом варианте подпрограммы будет состоять из трех команд, а во втором – из двух (stosb и loop). Пару команд stosb и loop можно заменить одной командой rep stosb, т. е. использовать микропрограммный цикл, выполняющийся быстрее программного.

В примере 3.8 приведена подпрограмма для быстрого рисования горизонтальных линий в направлении слева направо с использованием одного или Двух микропрограммных циклов. При обращении к ней входные параметры задаются так же, как для подпрограмм примера 3.6.

Пример 3.8. Подпрограмма быстрого рисования горизонтальной линии.

horline: push dx сохранение содержимого регистра dx
mov dx, di копирование адреса в регистр dx
add dx, ex сумма текущего адреса и количества точек
jc @F › прямая расположена в двух окнах
xor dx, dx очистка регистра dx
@@: sub ex, dx количество точек в текущем окне
rep stosb рисуем всю прямую или ее начало
or di, di адрес в пределах текущего окна?
jne @F › да, линия нарисована полностью
call NxtWin установка следующего окна
mov ex, dx количество не нарисованных точек
rep stosb рисуем остаток линии
@@: pop dx восстановление содержимого dx
ret возврат из подпрограммы
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.