Графические устройства

         

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

При построении обычных рисунков их образы копируются в видеопамять, но если таким способом построить рисунок, образ которого приведен в примере 6.3, то изображение белой стрелки будет расположено на фоне черного прямоугольника. Очевидно, что работать с подобным изображением

курсора неудобно и черный фон, окружающий стрелку, надо убрать. Для исключения окружающего фона применяются маскировка, или специальные способы построения изображения курсора.

Один из таких способов мы уже использовали при построении текстового курсора, он описан в разделе, пример 5.24. Здесь нас интересует более универсальный вариант подобной подпрограммы, позволяющий строить изображение курсора произвольного размера и формы. Для записи кодов точек в видеопамять, по-прежнему, будет использоваться логическая операция XOR, вычисляющая функцию "исключающее ИЛИ" (exclusive OR).

Предварительные замечания

Образ рисунка курсора можно хранить в любом сегменте оперативной памяти.


Учитывая его небольшой размер (294 байта). мы будем считать, что он расположен в сегменте данных (см. пример 6.3) и имеет имя pntimage. Маска при построении не используется, поэтому массив pntmask нас в данном случае не интересует.

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

PntXsize dw 14 ; количество точек в строке рисунка курсора
pntYsize dw 21 ; количество строк в рисунке курсора

В приведенном описании значения переменных соответствуют размерам рисунка, показанного в примере 6.3.

Курсор является особым рисунком, его координаты в видеопамяти могут использоваться в различных целях. Поэтому они хранятся в специальных переменных, значение которых может изменяться только при перемещении манипулятора "мышь". В примере 6.8 будет описано несколько переменных, используемых при работе с курсором. Здесь нас интересуют только две из них. Переменная winpnt содержит текущее окно видеопамяти, a offspnt — адрес (смешение) точки левого верхнего угла рисунка курсора в этом окне.

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

Текст подпрограммы, изменяющей состояние курсора на противоположное, приведен в примере 6.4. При каждом нечетном вызове Tglpntr рисунок курсора появляется на экране, а при каждом четном на ею месте восстанавливается исходный фон. Явно задаваемые входные параметры отсутствуют. Регистр es должен содержать код видеосегмента.

Пример 6.4. Подпрограмма переключения состояния курсора

Tglpntr: pusha сохранение содержимого регистров
push Cur_win сохранение исходного окна
ir.ov ax, Winpnt ax = окно с рисунком курсора
mov Cur_win, ax Cur_win = Winpnt
call setwin установка исходного окна
lea si, pntimage si = адрес массива pntimage
mov di, Offspnt di = адрес Е сегменте видеопамяти
mov ex, pntYsize ex = кол-во повторов внешнего цикла
mov bx, horsize вычисляем константу для
sub bx, pntXsize коррекции адресов строк
Displ 1 : push ex сохраняем счетчик строк
mov ex, pntXsize сх = количество точек в строке рисунка
Displ 2: lodsb ! ! al = код очередной точки рисунка
xor es : [di] , al ! ! корректируем байт видеопамяти
inc di ! ! увеличение адреса видеопамяти
jnz @F -> адрес в пределах текущего сегмента
call nxtwin конец сегмента, смена окна
@@: loop Displ 2 управление повторами цикла
pop ex восстанавливаем счетчик строк
add di , bx адрес начала следующей строки
jnc @F -> адрес в пределах текущего сегмента
call nxtwin конец сегмента, смена окна
@@: loop Displ 1 управление повторами цикла
pop Cur win восстановление Cur win
popa восстановление содержимого регистров
call setwin восстановление исходного окна
ret возврат из подпрограммы

В подпрограмме примера 6.4 используется только 5 регистров — ах, bх, сх, si и di, но для сокращения ее текста первая команда pusna сохраняет в стеке содержимое всех регистров. Затем в стек помещается исходное значение переменной Cur win, а ей присваивается новое значение и устанавливается соответствующее окно видеопамяти. В регистры si, di записываются адреса оперативной и видеопамяти, а в сх — количество строк в рисунке курсора. В конце подготовки в регистре bх формируется разность horsize - pntxsize, используемая в цикле построения для коррекции адресов строк видеопамяти.

Построение рисунка выполняют два вложенных цикла. Внешний имеет метку oispi_i. Он начинается с сохранения в стеке и изменения содержимого регистра сх, после чего выполняется внутренний цикл.

Цикл построения строки имеет метку Dispi_2. Его первая команда lodsb считывает в регистр al байт, адрес которого находится в dsrsi, и увеличивает содержимое регистра si на 1. Затем логическая операция XOR записывает содержимое регистра al в видеопамять. Регистр-посредник al нужен потому, что у команды хог (как и у команды mov) оба операнда не могут находиться в памяти.

После вывода очередной точки адрес видеопамяти увеличивается на 1, и если его значение осталось в пределах сегмента, то команда jnz @F обходит call nxtwin. В противном случае команда call nxtwin выполняется и устанавливается следующее окно. Последняя команда (loop Disp_2) повторяет выполнение цикла до тех пор, пока не будет нарисована вся строка.

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

После построения (или удаления) курсора из стека выталкивается содержимое переменной cur_wir. и всех сохраненных регистров, восстанавливается исходное окно видеопамяти и происходит возврат на вызывающий модуль.

Недостатки немаскируемого курсора

чевидными преимуществами работы с немаскируемым курсором являются следующие:

  • для построения и удаления курсора нужна одна подпрограмма;
  • подпрограмма выполняется сравнительно быстро;
  • в оперативной памяти хранится только образ рисунка.

Однако такой способ построения имеет один существенный недостаток, сводящий на нет перечисленные преимущества.

Идея использования немаскируемого курсора основана на том, что при определенных значениях операнда-источника команда хог инвертирует код операнда-приемника или не изменяет его (см. раздел). В описанной подпрограмме источником являются точки заготовки рисунка, а приемником — точки видеопамяти. Образ рисунка черно-белый, коды его точек имеют значения либо 00, либо 0FFh. Поэтому при построении рисунка цвета точек экрана, расположенных под стрелкой, инвертируются, а окружающих стрелку не изменяются. Таким образом, цвет рисунка немаскируемого курсора на экране зависит от исходного цвета точек в том месте экрана, на котором он создается.

Вспомним табл. 4.1 из главы 4. При ее описании говорилось, что два цвета являются дополнительными, если при их наложении получается белый цвет. В частности, дополнением к черному цвету является белый, к синему — желтый, к красному — циан, к зеленому — мажента. Исходя из этого, можно представить, как изменяется цвет курсора в зависимости от исходного цвета точек экрана. Если же на экране находится какая-то картинка, т. е. цвет экрана не однороден, то и изображение курсора будет неоднородным. На пестром фоне оно может "потеряться" — стать трудно различимым для глаза.

При работе в режимах PPG описанная подпрограмма инвертирует не код цвета, а номер регистра видеокарты. Полученный при инверсии цвет будет зависеть от установленной (системной) палитры. Эта особенность успешно использовалась, например, в ранних версиях Windows — системная палитра подбиралась так, чтобы можно было использовать немаскируемый курсор.

В заключение заметим, что после описания маскируемого курсора в разделе 6.1.5 мы продолжим обсуждение некоторых вопросов, связанных с построением изображения курсора.


Содержание раздела