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

         

А 9 Построение рисунка формата ВМР сверху вниз



Пример А.9. Построение рисунка формата ВМР сверху вниз

Smlbmp : pusha сохранение "всех" регистров
PushReg <fs,gs,Cur wi n>; сохранение fs, gs, Cur win
mov ax, horsize ax = horsize
sub ax, iwidth ax = horsize — iwidth
mul bytppnt ax = (horsize — iwidth) * bytppnt, dx = 0
mov dx , ax dx = ax, для коррекции адреса строки
mov ex , si ex = si, размер образа рисунка
mov SwpOffs, 0 начало считываемых данных
call readf чтение образа рисунка
jnc ok -> чтение без ошибок
; Здесь должны выполнят! эСЯ действия в случае ошибки при чтении
ok: mov fs, SwpSeg fs = сегмент буфера обмена
mov gs, GenSeg ! ! gs = сегмент таблицы цветов
mov ex, iheight сх = количество строк в рисунке
invout : push ex сохраняем счетчик повторов


mov ex, iwidth сх = размер строки рисунка
sub si, fwidth адрес начала новой строки
call drawline ! ! или call bx — построение строки
pop ex восстанавливаем счетчик повторов
add si, rmndr учитываем "лишние байты"
sub si, fwidth адрес начала построенной строки
add di, dx коррекция адреса видеопамяти
jne @F -> адрес в пределах сегмента
call NxtWin установка следующего окна
@@: loop invout ; управление повторами цикла
PopReg <Cur win,gs,fs> ; восстановление Cur win, gs, fs
popa ; восстановление "всех" регистров
call setwin ; восстановление исходного окна
ret ; возврат из подпрограммы

Выполнение примера А.9 начинается с сохранения в стеке содержимого регистров общего назначения, сегментных регистров fs, gs и переменной cur_win. Следующие четыре команды вычисляют константу для коррекции адресов строк видеопамяти по способу, описанному в примере 7.13.

Для чтения образа файла в регистр сх помещается его размер, очищается переменная Swpoffs и происходит обращение к подпрограмме readf. Если чтение прошло без ошибок, то команда jnc ok обойдет строку, состоящую только из комментария. Что делать при ошибках чтения, решать вам.

В подпрограммах построения строк (drawiine) регистр fs используется при чтении кодов точек из оперативной памяти, а регистр gs — при работе с таблицей цветов. Поэтому перед началом основного цикла в них записываются коды соответствующих сегментов.
Цикл построения рисунка имеет метку invout. Работа с адресами в нем организована так, что при каждом повторе регистр di содержит адрес очередной строки видеопамяти, а регистр si — адрес последней обработанной строки образа рисунка (при первом входе это размер рисунка в байтах).

Перед вызовом подпрограммы drawiine содержимое si уменьшается на размер строки в файле (fwidth) и указывает начало очередной строки. При выполнении подпрограммы drawiine регистр si увеличится на iwidth. Поэтому после возврата из drawiine значение si увеличивается на rmndr (количество лишних байтов) и уменьшается на fwidth. В результате регистр si будет содержать адрес начала последней обработанной строки.

Адрес начала следующей строки видеопамяти, как обычно, увеличивается на константу переадресации, которая хранится в регистре dx. Если при сложении (add di, dx) происходит переполнение, то устанавливается следующее окно видеопамяти.
Команда loop invout повторяет выполнение цикла нужное количество раз, после чего восстанавливаются сохраненные в стеке величины, исходное окно видеопамяти и происходит возврат на вызывающий модуль.

По сравнению с обычным циклом построения рисунка (см. пример 7.23) в данном случае добавились три команды, корректирующие значение регистра si. При желании их количество можно сократить до двух. Подумайте, как это сделать, но не забывайте, что fwidth - rmndr не обязательно равно iwidth. Вспомните, как вычислялись эти величины.

Замечание 1
Замечание 1

Напомним, что имя подпрограммы построения строки не обязательно указывать в явном виде. Команду call drawline можно изменить на call bx, а перед обращением формировать в регистре bх адрес подпрограммы построения строки (см. раздел в данном приложении).



Содержание раздела