Построение рисунков, использующих палитру. Построение рисунка сверху вниз.
Подпрограмма 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х адрес подпрограммы построения строки (см. раздел в данном приложении).