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

Построение рисунков с использованием палитры

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

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