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

Построение рисунков, использующих палитру. Построение рисунка сверху вниз.

Подпрограмма Smlbmp

Текст подпрограммы, выполняющей построение небольшого рисунка формата BMP описанным способом, приведен в примере А.9. Перед ее вызовом адрес левого верхнего угла рисунка в видеопамяти помещается в регистр di и устанавливается окно, которому принадлежит этот адрес. Регистр es должен содержать код видеосегмента. В регистре si указывается размер образа рисунка в байтах.

Пример А.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. Вспомните, как вычислялись эти величины.

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

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