Манипуляции с палитрой цветов
Выполнение примера 4.7 начинается с сохранения в стеке содержимого всех используемых регистров. Команда pusha не работает с сегментными регистрами, поэтом, содержимое gs сохраняет макрос pushReg. Он же помещает в стек исходное значение переменной numcol для того, чтобы его можно было восстановить) случае переполнения системной палитры. Третья команда очищает регистр bx, который используется как счетчик байтов массива Index.
Основные действия выполняются в двух вложенных циклах. Внешний имеет метку anis_i., внутренний – anis_2.
Внешний цикл повторяется столько раз, сколько цветов (строк) содержит палитра добавляемого рисунка. Эта величина указывается в регистре сх при вызове подпрограммы. Оба цикла используют общий регистр сх для хранения счетчика повторов, поэтому выполнение внешнего цикла начинается с сохранения в стеке его содержимого. Кроме того, в стеке сохраняется содержимое bx поскольку его изменяет следующая команда. Обе величины сохраняет макрос PushReg.
После сохранения содержимого сх и bх в регистр ebx считывается код очередной строк палитры добавляемого рисунка. Коды базовых цветов в ней сокращаются до шести разрядов путем сдвига содержимого регистра ebx на два разряда вправо и выделения шести младших разрядов каждого байта.
Код белого иета расположен в конце системной палитры, поэтому во внешнем цикле надо проверить, не является ли анализируемый цвет белым. Если это так, то выполняется переход на метку anis_4 для записи номера белого цвета: в очередной байт массива index. В противном случае происходит подготовка к выполнению цикла сравнений. Для этого в регистры gsrsi загружается адрес системной палитры, в регистр сх помещается количество хранящихся в ней цветов, а регистр dx очищается.
Первые пять команд внутреннего цикла выполняют сравнение кода цвета, находящегося в регистре ebx, с кодами строк системной палитры. При совпадении происходит переход на метку anls_4 для записи текущего номера строки системной палитры в очередной байт массива index. В противном случае сравнение продолжается, пока не будут проверены все коды.
После завершения цикла сравнений надо проверить, осталось ли в Syspal место для записи нового цвета. Если осталось, то выполняется переход на метку anis_3. В противном случае устанавливается признак переноса, восстанавливаются сохраненные в стеке величины и происходит возврат на вызывающий модуль.
Если в syspai есть свободное место, то код добавляемого цвета записывается в первую свободную строку, значение numcol увеличивается на 1 и происходит обращение к BIOS для записи кода в регистр цвета видеокарты, номер которого совпадает с номером строки системной палитры. Затем выполняется фрагмент, первая команда которого имеет метку anis_4.
Из стека восстанавливается содержимое регистра bx и в указанный в нем байт массива index записывается номер строки системной палитры, содержащей анализируемый цвет. Находящийся в регистре di адрес увеличивается на 4 так, чтобы он указывал начало следующей строки добавляемой палитры. Из стека восстанавливается содержимое регистра сх и команда loop anis_i повторяет выполнение внешнего цикла до тех пор, пока не будут обработаны все строки (цвета) палитры добавляемого рисунка.
Если добавление палитры закончилось успешно, то изменять значение переменной numcol нельзя, поэтому сохраненное в стеке значение выталкивается в регистр ах. Затем восстанавливается содержимое регистра gs и всех остальных регистров и происходит возврат на вызывающий модуль.
Если для установки добавляемой палитры недостаточно места, то при возврате из подпрограммы AnisPal будет установлен С-разряд регистра флагов и сохранено исходное значение numcol. Поэтому при неудачной попытке установки палитры цвета, записанные в системную палитру и регистры видеокарты, не учитываются при последующих обращениях к подпрограмме AnisPal.
Изменения в тексте подпрограммы
Как уже говорилось, пример 4.7 составлен исходя из предположения, что палитра добавляемого рисунка хранится в файле в формате b, g, r, 0. Если по каким-то соображениям вам нужно работать с палитрами формата г, д, ь, то в тексте примера 4.7 надо изменить две команды. Комментарий к заменяемым командам начинается с двух восклицательных знаков.
Для размещения в регистре ebx трех базовых цветов текущей строки палитры добавляемого рисунка команда mov ebx, fs: [di] заменяется приведенной в примере 4.8 группой, состоящей из пяти команд.
Пример 4.8. Преобразование формата r, g, b в формат b, g, r, 0.
xor ebx, ebx; очистка Реги тра ebx mov bh, fs: [di]; чтение в bh кода красного цвета mov b1, fs: [dl+1]; чтение в bl кода зеленого цвета shl ebx, 08; сдвиг ebx на 8 разрядов влево mov b1, fs: [di+2]; чтение в bl кода синего цвета
И второе изменение. Строка палитры формата r, g, b занимает в памяти три байта, поэтому команду переадресации add di, 04 надо заменить командой add di, 03.