Построение рисунков. Варианты построения строк.
Распаковка 2-цветных строк
Если при построении рисунка использовано только два цвета, например черный и белый, то код точки помещается в одном разряде и может принимать только два значения 0 и 1. В таких случаях для сокращения размеров файла в одном байте располагаются коды восьми точек. В старшем разряде байта находится код первой точки, а в младшем – последней, поэтому выделять коды точек надо начиная со старшего разряда. В зависимости от количества точек в строке последний байт может быть заполнен частично. Не следует считать, что двухцветные рисунки обязательно черно-белые – их цвета зависят от кодов, находящихся в прилагаемой к файлу палитре.
Подпрограмма для распаковки строки в процессе построения 2-цветного рисунка приведена в примере 3.18. Перед ее вызовом устанавливается окно видеопамяти, в котором должна располагаться строящаяся строка, а адрес первой точки помещается в регистр di. Пара регистров fs:si должна содержать адрес оперативной памяти, начиная с которого хранится упакованная строка. В регистре сх указывается количество точек в строке.
Пример 3.18. Подпрограмма построения строки 2-цветного рисунка.
drwlinl: | push | bx | сохраняем содержимое bp |
mov | bx, ex | bp = ex (количество точек в строке) | |
Ipdrwll: | lods | byte ptr fs: [si] | читаем в al код очередного байта |
mov | ah, al | копируем коды из al в ah | |
mov | ex, 08 | количество повторов цикла распаковки | |
outSpnt: | xor | al, al | очищаем регистр al |
shl | ah, 01 | сдвигаем ah на разряд влево | |
adc | al, 00 | прибавляем переполнение к al | |
stosb | записываем код очередной точки | ||
or | di, di | начало нового сегмента? | |
jne | @F; | › нет, обход команды call NxtWin | |
call | NxtWin; | установка следующего окна | |
@@: | dec | bx | bx = bx -1 |
je | drlret | если bx = 0, то строка построена | |
loop | outSpnt | управление внутренним циклом | |
jmp | short Ipdrwll | › на обработку следующего байта | |
drlret: | pop | bx | восстановление содержимого bx |
ret | выход из подпрограммы |
Подпрограмма примера 3.18представляет собой два вложенных цикла. Имя внешнего цикла ipdrwii, а внутреннего – outSpnt.
Внешний цикл считывает очередной байт образа строки, копирует его в регистр ah и задает количество повторов внутреннего цикла.
Во внутреннем цикле производится распаковка очередной группы точек и запись их кодов в видеопамять. Распаковку выполняют три первые команды внутреннего цикла. Первая из них очищает регистр ai, вторая сдвигает содержимое регистра ah на разряд влево. При сдвиге старший разряд регистра ah переносится в С-разряд регистра флагов, поэтому если он содержал единицу, то вырабатывается признак переполнения. Третья команда (adc ai, оо) прибавляет содержимое С-разряда к регистру ai. В результате, в зависимости от кода очередной точки, в регистре ai окажется 0 или 1. Полученный код точки команда stosb записывает в видеопамять. Затем проверяется текущий адрес видеопамяти и при необходимости устанавливается следующее окно видеопамяти.
После записи каждой точки содержимое регистра bx уменьшается на 1 и если оно окажется равным нулю, то происходит переход на метку drlret для завершения подпрограммы. В противном случае команда loop управляет выводом восьми точек. После этого происходит короткий безусловный переход на начало внешнего цикла для обработки следующего байта.