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

Маскируемый курсор

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

Описанные действия выполняются в одном цикле, который повторяется для каждой точки прямоугольной области, в которой располагается рисунок курсора. Текст подпрограммы приведен в примере 6.5. Входные параметры явно не задаются, они находятся в тех переменных, которые были описаны в предыдущем разделе. Регистр es должен содержать код видеосегмента (хранящийся в vbuff).

Пример 6.5. Подпрограмма построения рисунка маскируемого курсора.

Showpnt: pusha сохранение содержимого регистров
push Cur win сохранение исходного окна
mov ax, Winpnt ах = окно с рисунком курсора
mov Cur win, ax Cur win = Winpnt
call setwin установка исходного окна
xor si, si очистка регистра si
mov di, Offspnt di = адрес в сегменте видеопамяти
mov ex, pntYsize сх = кол-во повторов внешнег о цикла
mov bx, horsize вычисляем константу для
sub bx, pntXsize коррекции адресов строк
Sh_1: push ex сохраняем значение счетчика строк
mov ex, pntXsize ex = количество точек в строке рисунка
Sh_2: mov al, es: [di]!! al = код точки исходного фона
mov pntbuff[si], al!! сохраняем его в pntbuf f
and al, pntmask[si]!! накладываем маску
xor al, pnt image [si]!! формируем новый код точки
stosb!! и записываем его в видеопамять
inc si!! коррекция адреса рисунка
or di, di адрес в пределах текущего окна?
jnz @F › да, обходим следующую команду
call nxtwin установка следующего окна
@@: loop sh 2 управление повторами цикла
pop ex восстанавливаем счетчик строк
add di, bx корректируем адрес видеопамяти
jnc @F › адрес в пределах текущего окна
call nxtwin установка следующего окна
@@: loop sh 1 управление внутренним циклом
pop Car win восстановление значения Cur win
popa восстановление всех регистров
call setwin восстановление исходного окна
ret возврат из подпрограммы

Начало примера 6.5 отличается от примера 6.4 только одной командой. Вместо записи адреса массива pntimage в регистр si последний просто очищается. Это сделано потому, что регистр si используется для доступа к трем массивам, а не к одному, как это было в примере 6.4.

Принципиальное различие между примерами в основных действиях, выполняемых во внутреннем цикле, который в данном случае имеет метку sh_2. Первая команда внутреннего цикла считывает код очередной точки из видеопамяти в регистр al, а вторая сохраняет его в очередном байте массива pntbuf f. После этого в регистр al помещается результат вычисления логической функции "И" от исходного значения регистра и содержимого очередного байта маски. В зависимости от кода байта маски регистр al либо будет очищен, либо его исходное значение не изменится – третьего не дано. Следующая команда завершает формирование нового кода точки, она вычисляет логическую функцию "исключающее ИЛИ" от содержимого регистра al и очередного байта массива pntimage. Остается записать новый код точки в видеопамять, что и делает команда stosb, одновременно она увеличивает содержимое регистра di на 1.

Основные действия выполнены, шестая команда увеличивает на 1 адрес оперативной памяти (содержимое регистра si). Адрес видеопамяти (содержимое di) увеличила команда stosb, но надо проверить, остался он в пределах текущего видеосегмента или нет. Признаком выхода за пределы сегмента является нуль в регистре di, при этом подпрограмма nxtwin установит следующее окно видеопамяти. Повторами внутреннего цикла управляет команда :оор Sh_2.

После построения строки из стека восстанавливается значение счетчика повторов, вычисляется адрес начала следующей строки в видеопамяти, команда loop sh_i повторяет выполнение внешнего цикла до тех пор, пока на экран не будут выведены все строки изображения курсора.

В заключение из стека выталкиваются исходные значения переменной cur_wir. У всех регистров, восстанавливается исходное окно видеопамяти и происходит возврат на вызывающий модуль.

Массивы в другом сегменте. Текст примера 6.5 составлен из расчета па то, что массивы pntimage, pntmask и pntbuff расположены в разделе данных n для доступа к ним используется регистр ds, имя которого не указывается перед операндами. Если вы предпочитаете расположить указанные массивы в другом сегменте, то в трех командах примера 6.5 перед именами массивов надо явно указать имя выбранного вами сегментного регистра. Например, mov fs:pntbuf f [si], ai, если для доступ а к массиву pntbuff используется сегментный регистр fs.

Важно
Еще раз напоминаем, что все три массива должны располагаться в одном сегменте
.

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