Построение рисунков с использованием палитры
Ранее были подробно описаны способы построения не сжатых рисунков, в образах которых точки расположены в естественном порядке. При этом мы различали рисунки ограниченного и произвольного размера. Соответствующие варианты подпрограмм приведены в примерах 3.21 и 3.22, они предназначены для выполнения в режимах PPG. В данном разделе описаны такие варианты этих примеров, которые можно использовать в любых видеорежимах.
Построение строки рисунка
Для построения строки рисунка в примерах 3.21 и 3.22 вызывалась подпрограмма drawiine. Большинство описанных ранее ее вариантов выполняет копирование кодов точек образа рисунка в видеопамять. Исключением являются примеры 2.17 и 2.18, в которых при построении строки выполняется распаковка 16 – и 2-цветных рисунков. В данном случае нам нужен вариант подпрограммы, выполняющий перед записью в видеопамять перекодирование точек образа рисунка по таблице цветов.
Текст подпрограммы приведен в примере 7.21. Перед ее вызовом в регистрах указываются следующие данные: сх – размер строки, di – адрес ее первой точки в видеопамяти, fs:si – адрес начала рисунка в оперативной памяти, gs – сегмент оперативной памяти, содержащий таблицу цветов. Адрес начала таблицы в этом сегменте подпрограмма выбирает сама из переменной GenOffs. Как обычно, предварительно надо установить окно видеопамяти, к которому относится указанный в di адрес, а в регистре es должен находиться код видеосегмента.
Пример 7.21. Построение строки с перекодированием по таблице цветов.
drawline: push eax сохранение содержимого еах drwlin: lods byte ptr fs:[di]; al = код точки образа рисунка and eax, OFFh очистка старших разрядов еах shl ax, wrdppnt учет размера строки таблицы add ax, GenOffs ax = смещение начала таблицы mov ах, дз: [еах]!! или mov eax, gs: [eax] для True Color stosw!! или stosd для True Color or di, di достигнута граница окна? jne @F › нет, обход следующей команды cal I NxtWin установка следующего окна @@: loop drwlin управление повторами цикла pop eax восстановление содержимого еах ret возврат из подпрограммы
В цикле примера 7.21 регистр еах используется для указания адреса при чтении кода цвета точки. Адрес формируется в младшем слове регистра, а его старшее слово должно быть очищено. Поэтому после чтения в al кода образа точки старшие разряды регистра еах очищаются с помощью операции "конъюнкция". В зависимости от установленного видеорежима, третья команда сдвигает содержимое ах на 1 или 2 разряда влево. Остается прибавить к ах смещение таблицы в сегменте gs, и адрес требуемого кода будет сформирован. Код считывается в регистр ах (или в еах) и оттуда записывается в видеопамять с помощью строковой операции stosw или stosd.
Далее, как обычно, проверяется адрес видеопамяти и в случае необходимости устанавливается следующее окно. Повторами цикла управляет команда loop.
В тексте примера две команды зависят от видеорежима, комментарий к ним начинается с двух восклицательных знаков. Избавиться от переменных команд невозможно, но для выбора их нужной пары можно использовать директивы условного ассемблирования (см. пример 7.8).
Упрощение подпрограммы
В примере 7.22 приведен текст упрощенного варианта подпрограммы, выполняющей перекодировку и запись одной точки, код которой указан в регистре ai.
Пример 7.22. Перекодировка по таблице и запись точки в видеопамять.
wrtpnt: push eax сохранение содержимого еах and eax, OFFh очистка старших разрядов еах shl ax, wrdppnt учет размера строки таблицы add ax, GenOffs ax = смещение начала таблицы mov ax, gs: [еах]!! или mov eax, gs:[eax] для True Color stosw!! или stosd для True Color pop eax восстановление содержимого еах ret возврат из подпрограммы
Построение небольшого рисунка
Подпрограмма построения рисунка, образ которого помещается в одном сегменте, приведена в примере 7.23.
Перед ее вызовом устанавливается окно видеопамяти, содержащее левый верхний угол рисунка, а адрес этого угла помещается в регистр di. Адрес начала образа рисунка в оперативной памяти записывается в регистры fs:si. Его ширина и высота указываются, соответственно, в dx и сх. Адрес начала таблицы подпрограмма выбирает из переменных GenSeg и GenOffs. Как обычно, должно быть установлено окно видеопамяти, к которому относится указанный в di адрес, а регистр es должен содержать код видеосегмента.
Пример 7.23. Построение рисунка из файла небольшого размера.
drawing: PushReg <di,si,bx,ex,gs,Cur_win>; сохранение в стеке call calloffs вычисление константы offsline mov gs, GenSeg gs = сегмент таблицы цветов drwout: push ex сохраняем счетчик повторов mov .ex, dx задаем размер строки рисунка call drawline построение очередной строки pop ex восстанавливаем счетчик повторов add di, bx коррекция адреса видеопамяти jnc @F › адрес в пределах сегмента call NxtWin установка следующего окна @@: loop drwout; управление повторами цикла PopReg <Cur win,gs,cx,bx,si,di>; восстановление из стека call setwin; восстановление исходного окна ret; возврат из подпрограммы
Если вы сравните тексты примеров 3.21 и 7.23, то обнаружите, что они различаются только второй и третьей командами, а в списках параметров макровызовов PushReg и PopReg в примере 7.23 добавился регистр gs. Ну и, конечно же, имя drawiine относится к двум разным подпрограммам.