В исходном виде рисунок курсора и маска не удобны для многократного использования. Их надо распаковать, перевернуть, по возможности сократить и хранить в оперативной памяти до конца выполнения задачи.
Перед построением изображения курсора, как и любого рисунка, должна быть установлена палитра используемых цветов (см. главу 4). В данном случае палитра хранится в формате BMP для Windows, который описан в приложении А.
Замечание
Напомним, что в зависимости от способа установки палитры могут измениться
коды точек рисунка курсора (но не маски).
Поворот рисунка и маски. Рисунок на экране проще строить в естественном порядке, т. е. в направлении слева направо и сверху вниз. В исходном виде рисунок и маска хранятся "вверх ногами", поэтому перед распаковкой их надо повернуть. При повороте переставляют 16 пар строк: первую строку с последней, вторую — с предпоследней и т. д.
В примере 6.2 показано, как можно программно переставить строки маски
или черно-белого рисунка. Перед выполнением примера исходный файл должен
Пример 6.2. Поворот черно-белого рисунка или маски
mov si, di копируем адрес первой строки
add si, 124 получаем адрес последней строки
mov ex, 16 количество пар строк
turn : mov eax, fs : [di] еах = строка 1
xchg eax, f s : [si j еах = строка 2; fs: [si] = строка 1
mov fs : [di] , eax fs : [di] = строка 2
add di, 04 адрес следующей строки
sub si, 04 адрес предыдущей строки
loop turn управление повторами цикла
Выполнение примера 6.2 начинается с подготовки адреса последней строки
и задания количества переставляемых пар. Перестановку выполняет цикл,
его первая команда имеет метку turn. Она копирует в регистр еах первую
строку пары. Следующая команда переставляет содержимое еах и второй строки
пары. Третья команда копирует содержимое еах в первую строку. В результате
переставлена пара строк. Затем корректируются адреса строк, и команда
loop повторяет выполнение цикла 16 раз.
При перестановке расположение байтов в строке не изменяется, поскольку
пересылку выполняет одна команда. Для переворота цветного рисунка этот
пример не подходит, т. к. для перестановки 16-ти байтов пары строк надо
организовать внутренний цикл, а во внешнем подготавливать адреса переставляемой
пары.
Повернутые рисунок и маску надо распаковать и сохранить в оперативной памяти. Для их хранения выделяется два массива, размером по 1024 байта (один байт на точку). В дальнейшем мы будем называть их pntimage и pntmask, первый содержит распакованный рисунок курсора, а второй — маску.
При распаковке черно-белого рисунка содержимое каждого байта обрабатывается, начиная со старшего разряда, и значение каждого бита (0 пли I) помешается в соответствующий байт массива pntimage.
При распаковке 16-цветного рисунка в байты массива pntimage записываются сначала старшая, а затем младшая тетрада каждого байта упакованного рисунка. Коды распакованных точек изменяются от о до огь.
Подпрограммы распаковки строк 16- и 2-цветных рисунков приведены в примерах 3.17 и 3.18, но они записывают результат в видеопамять. Применительно к данному случаю их надо изменить так, чтобы результат записывался в оперативную память, и организовать цикл для распаковки всего рисунка или маски.
После распаковки рисунка будут получены коды цветов, являющиеся адресами строк прилагаемой палитры. Маловероятно, чтобы они совпали с кодами цветов системной палитры, с которой работает задача. Едва ли в ней код белого цвета будет равен 1 или OFh, как в прилагаемой к рисунку палитре. Поэтому у вас есть две возможности: либо преобразовать распакованные коды рисунка так, чтобы они соответствовали системной палитре, либо в системной палитре зарезервировать 2 или 16 первых регистров цвета для работы с курсором. Второй способ используется в Windows при работе в режимах PPG.
Последовательность действий при распаковке маски та же, что и при распаковке черно-белого рисунка. Если текущий бит маски содержит 0, то соответствующий байт массива pntmask очищается, но если текущий бит маски содержит 1, то устанавливаются все разряды соответствующего байта массива pntmask (в него записывается код OFFh). Это объясняется специфическим назначением маски — при ее наложении байты видеопамяти либо полностью очищаются, либо остаются без изменения.
Сокращение рисунка и маски.
При выполнении графических задач курсор перемещается достаточно часто, поэтому желательно сократить до минимума действия, связанные с его построением и перемещением. Для этого, в частности, можно исключить из исходного рисунка не используемые (пустые) строки и столбцы.
Как правило, размеры рисунка меньше стандартного поля 32x32 точки. Например, изображение стрелки, хранящейся в файле Left_00.cur (см. пример 6.1) помещается в прямоугольнике шириной в 14 и высотой в 21 точку. Следовательно, для его хранения в памяти достаточно выделить не 1024, а всего 294 байта. Очевидно, что при сокращении рисунка не только уменьшается занимаемое им пространство оперативной памяти, но и ускоряется процесс его построения и удаления. Рисунок и маска взаимосвязаны, поэтому при исключении строки пли столбца рисунка надо исключить соответствующую строку или столбец маски.
Пример описания рисунка и маски. В примере 6.3 заготовка рисунка и маска описаны на языке ассемблера. Это распакованный файл из примера 6.1, в котором переставлены не только строки, но и столбцы, для того чтобы стрелка курсора была наклонена влево, а не вправо.
Пример 6.3. Описание рисунка и маски курсора
Pnt image db 00, 00, 00,00, 00, 00, 00 00,00, no, nn nn
no oo
db 00, 00, 00,00, 00, 00, 00, 00,00, 00, 00, 00, 00,00
db 00, 00, FF, 00, 00, 00, 00, 00,00, 00, 00, 00, 00,00
db 00, 00, FF, FF, 00, 00, 00, 00,00, 00, 00, 00, 00,00
db 00, 00, FF,FF, FF, 00, 00, 00,00, 00, 00, 00, 00,00
db 00, 00, FF,FF, FF, FF, 00, 00,00, 00, 00, 00, 00,00
db 00, 00, FF, FF, FF, FF, FF, 00,00, 00, 00, 00, 00,00
db 00, 00, FF, FF, FF, FF, FF, FF, 00, 00, 00, 00, 00,00
db 00, 00, FF, FF, FF, FF, FF, FF, FF, 00, 00, 00, 00,00
db 00, 00, FF, FF, FF, FF, FF, FF, FF, FF, 00, 00, 00,00
db 00, 00, FF,FF, FF, FF, FF, FF, FF, FF, FF, 00, 00,00
db 00, 00, FF, FF, FF, FF, FF, FF, 00, 00, 00, 00, 00,00
db 00, 00, FF, FF, FF, 00, FF, FF, 00, 00, 00, 00, 00,00
db 00, 00, FF, FF, 00, 00, FF, FF, 00, 00, 00, 00, 00,00
db 00, 00, FF, 00, 00, 00, 00 FF, FF, nn 00 nn ПП ПО
db 00, 00, 00,00, 00, 00, 00, FF,FF, 00, 00, 00, 00,00
db 00, 00, 00,00, 00, 00, 00, 00, FF, FF, 00, 00, 00,00
db 00, 00, 00,00, 00, 00, 00, 00, FF, FF, 00, 00, 00,00
db 00, 00, 00, 00, 00, 00, 00, 00,00, FF, FF, 00, 00,00
db 00, 00, oo on nn nn nn 00,00, FF, FF, 00, 00,00
db 00, 00, 00,00, 00, 00, 00, 00,00, 00, 00, 00, 00,00
pntmask db FF, 00, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF
db FF, 00, 00, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF
db FF, 00, 00,00, FF, FF, FF, FF, FF, FF, FF, FF, FF,FF
db FF, 00, 00,00, 00, FF, FF, FF,FF, FF, FF, FF, FF,FF
db FF, 00, 00,00, 00, 00, FF, FF, FF, FF, FF, FF, FF,FF
db FF, 00, 00,00, 00, 00, 00, FF, FF, FF, FF, FF, FF, FF
db FF, 00, 00,00, 00, 00, 00, 00, FF, FF, FF, FF, FF,FF
db FF, 00, 00,00, 00, 00, 00, 00,00, FF, FF, FF, FF,FF
db FF nn 00,00, nn nn nn 00,00, on FF FF FF FF
db FF, 00, 00,00, 00, 00, 00, 00,00, 00, 00, FF, FF, FF
db FF, 00, 00,00, 00, 00, 00, 00,00, 00, 00, 00, FF, FF
db FF, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
FF
db FF, 00, 00, 00, 00, 00, 00, 00, 00, FF, FF, FF, FF, FF
dc FF, 00, 00, 00, 00, 00, 00, 00, 00, :-:-, FF, FF, FF, FF
db FF, 00, 00, 00, FF, FF, 00, 00, 00, 00, FF, FF, FF, FF
db FF, ou, 00, FF, FF, FF, 00, 00, 00, 00, FF, FF, FF, FF
db FF, 00, FF, FF, FF, FF, t F, 00, 00, 00, 00, FF, FF, FF
db FF, FF, FF, FF, FF, FF, FF, 00, 00, 00, 00, FF, FF, FF
db FF, FF, FF, FF, FF, FF, FF, FF, 00, 00, 00, 00, FF, FF
db FF, FF, F"F FF, FF, FF, FF, FF, 00, 00, 00, 00, FF, Ь г
db FF, FF, FF, FF, FF, FF, FF, FF, FF, 00, 00, FF, FF, FF
В примере 6.3 метки pntimage и pntmask предшествуют директиве db, поэтому двоеточие после них не ставится. Если вы будете включать текст примера в свою программу, то все коды FF надо заменить на OFFh или на десятичное число -1. Здесь это не сделано только из соображений наглядности, чтобы можно было увидеть образованный из цифр рисунок. Текст примера лучше всего включить в сегмент данных вашей программы. Для того чтобы рисунок курсора был черно-белым, нулевой регистр цвета видеокарты должен быть очищен, а в последнем (255-м) регистре должен находиться код белого цвета (3F,3F,3F) (см. раздел).
Подведем итог всему сказанному в данном разделе. Курсор, хранящийся в файле формата icon, не удобно использовать без предварительного преобразования рисунка и маски и установки палитры используемых цветов. Если вы хотите, чтобы ваша задача могла работать с файлами формата icon, то в нее придется включить специальную процедуру, выполняющие описанные в данном разделе действия. Если же нужен только один рисунок курсора, то его преобразование проще выполнить вне задачи, а в ее исходный текст включить результат, как это сделано в примере 6.3.
Преобразования выполняются вручную или с помощью специально составленной
программы, поскольку стандартные графические редакторы не работают с файлами
формата icon. Преобразование вручную занимает сравнительно немного времени.
Сначала исходный файл преобразуется в символьную форму, т. е. в файл,
содержащий шестнадцатеричные коды (дамп). А затем символьный файл редактируют
с помощью любого текстового редактора, например, входящего в Norton Commander
и вызываемого нажатием функциональной клавиши <F4>.