кция установки вектора MOV AL,1FH ;номер изменяемого вектора INT 21H ;установка вектора POP DS ;восстанавливаем DS ;---печать символов MOV AH,2 ;номер функции MOV DL,128 ;первый символ INT 21H ;вывод его MOV DL,129 ;второй символ INT 21H ;вывод его Для EGA функция 11H прерывания 10H манипулирует набором симво- лов. Эта функция может быть очень сложной, когда она используется для создания специальных режимов экрана, но ее основное примене- ние достаточно простое. Имеется четыре подфункции. Когда AL равен 0, то данные, определяемые пользователем переносятся из памяти в специальный блок символов. Когда AL равен 1 или 2, то наборы данных для символов 8*14 и 8*8 соответственно копируются из ПЗУ в блок символов. Когда AL равен 3, то функция устанавливает назна- чение блока в регистре выбора карты символов, как описано выше. В последнем случае надо просто поместить соотвествующие данные в BL и вызвать функцию. Для загрузки данных из ПЗУ поместите номер блока в BL и выполните функцию. Для загрузки своих данных надо чтобы ES:BP указывали на них, число передаваемых символов должно быть в CX, смещение (номер символа) в блоке должно быть в DX, число байтов на символ - в BH, а номер блока - в BL. После этого вызывайте прерывание 10H. Вот пример: ;---устанавливаем 128 пользовательских символов в блоке 0 MOV AX,SEG CHARACTER_DATA ;ES:BP должны указывать на данные MOV ES,AX ; MOV BP,OFFSET CHARACTER_DATA ; MOV CX,128 ;число символов MOV DX,128 ;начальное смещение MOV BL,0 ;номер блока MOV BH,8 ;матрица 8*8 MOV AL,1 ;номер подфункции MOV AH,11H ;номер функции INT 10H ;переносим данные 4.3.5 Сводка данных для описания символов. Ниже приведены 8-байтные последовательности, необходимые для описания символов для цветного графического адаптора. Их исполь- зование объяснено в [4.3.4]. Код ASCII Символ Последовательность (16-ная) 128 А 78 CC C0 CC 78 18 0C 78 129 Б 00 CC 00 CC CC CC 7E 00 130 В 1C 00 78 CC FC C0 78 00 131 Г 7E C3 3C 06 3E 66 3F 00 132 Д CC 00 78 0C 7C CC 7E 00 133 Е E0 00 78 0C 7C CC 7E 00 134 Ж 30 30 78 0C 7C CC 7E 00 135 З 00 00 78 0C 7C CC 7E 00 136 И 7E C3 3C 66 7E 60 3C 00 137 Й CC 00 78 CC FC C0 78 00 138 К E0 00 78 CC FC C0 78 00 139 Л CC 00 70 30 30 30 78 00 140 М 7C C6 38 18 18 18 3C 00 141 Н E0 00 70 30 30 30 78 00 142 О C6 38 6C C6 FE C6 C6 00 143 П 30 30 00 78 CC FC CC 00 144 Р 1C 00 FC 60 78 60 FC 00 145 С 00 00 7F 0C 7F CC 7F 00 146 Т 3E 6C CC FE CC CC CE 00 147 У 78 CC 00 78 CC CC 78 00 148 Ф 00 CC 00 78 CC CC 78 00 149 Х 00 E0 00 78 CC CC 78 00 150 Ц 78 CC 00 CC CC CC 7E 00 151 Ч 00 E0 00 CC CC CC 7E 00 152 Ш 00 CC 00 CC CC 7C 0C F8 153 Щ C3 18 3C 66 66 3C 18 00 154 Ъ CC 00 CC CC CC CC 78 00 155 Ы 18 18 7E C0 C0 7E 18 18 156 Ь 38 6C 64 F0 60 E6 FC 00 157 Э CC CC 78 FC 30 FC 30 30 158 Ю F8 CC CC FA C6 CF C6 C7 159 Я 0E 1B 18 3C 18 18 D8 70 160 а 1C 00 78 00 7C CC 7E 00 161 б 38 00 70 30 30 30 78 00 162 в 00 1C 00 78 CC CC 78 00 163 г 00 1C 00 CC CC CC 7E 00 164 д 00 F8 00 F8 CC CC CC 00 165 е FC 00 CC EC FC DC CC 00 166 ж 3C 6C 6C 3E 00 7E 00 00 167 з 38 6C 6C 38 00 7C 00 00 168 и 30 00 30 60 C0 CC 78 00 169 й 00 00 00 FC C0 C0 00 00 170 к 00 00 00 FC 0C 0C 00 00 171 л C3 C6 CC DE 33 66 CC 0F 172 м C3 C6 CC DB 37 6F CF 03 173 н 18 18 00 18 18 18 18 00 174 о 00 33 66 CC 66 33 00 00 175 п 00 CC 66 33 66 CC 00 00 176 ° 22 88 22 88 22 88 22 88 177 + 55 AA 55 AA 55 AA 55 AA 178 ? DB 77 DB EE DB 77 DB EE 179 ? 18 18 18 18 18 18 18 18 180 ? 18 18 18 18 F8 18 18 18 181 ч 18 18 F8 18 F8 18 18 18 182  36 36 36 36 F6 36 36 36 183 · 00 00 00 00 FE 36 36 36 184 ё 00 00 F8 18 F8 18 18 18 185 ? 36 36 F6 06 F6 36 36 36 186 ? 36 36 36 36 36 36 36 36 187 ' 00 00 FE 06 F6 36 36 36 188 ? 36 36 F6 06 FE 00 00 00 189 ? 36 36 36 36 FE 00 00 00 190 ? 18 18 F8 18 F8 00 00 00 191 ? 00 00 00 00 F7 18 18 18 192 А 18 18 18 18 1F 00 00 00 193 Б 18 18 18 18 FF 00 00 00 194 В 00 00 00 00 FF 18 18 18 195 Г 18 18 18 18 1F 18 18 18 196 Д 00 00 00 00 FF 00 00 00 197 Е 18 18 18 18 FF 18 18 18 198 Ж 18 18 1F 18 1F 18 18 18 199 З 36 36 36 36 37 36 36 36 200 И 36 36 37 30 3F 00 00 00 201 Й 00 00 3F 30 37 36 36 36 202 К 36 36 F7 00 FF 00 00 00 203 Л 00 00 FF 00 F7 36 36 36 204 М 36 36 37 30 37 36 36 36 205 Н 00 00 FF 00 FF 00 00 00 206 О 36 36 F7 00 F7 36 36 36 207 П 18 18 FF 00 FF 00 00 00 208 Р 36 36 36 36 FF 00 00 00 209 С 00 00 FF 00 FF 18 18 18 210 Т 00 00 00 00 FF 36 36 36 211 У 36 36 36 36 3F 00 00 00 212 Ф 18 18 1F 18 1F 00 00 00 213 Х 00 00 1F 18 1F 18 18 18 214 Ц 00 00 00 00 3F 36 36 36 215 Ч 36 36 36 36 FF 36 36 36 216 Ш 18 18 FF 18 FF 18 18 18 217 Щ 18 18 18 18 F8 00 00 00 218 Ъ 00 00 00 00 1F 18 18 18 219 Ы FF FF FF FF FF FF FF FF 220 Ь 00 00 00 00 FF FF FF FF 221 Э F0 F0 F0 F0 F0 F0 F0 F0 222 Ю 0F 0F 0F 0F 0F 0F 0F 0F 223 Я FF FF FF FF 00 00 00 00 224 р 00 00 76 DC CB DC 76 00 225 с 00 78 CC F8 CC F8 C0 C0 226 т 00 CC C0 C0 C0 C0 00 00 227 у 00 FE 6C 6C 6C 6C 6C 00 228 ф FC CC 60 30 60 CC FC 00 229 х 00 00 7E D8 D8 D8 70 00 230 ц 00 66 66 66 66 7C 60 C0 231 ч 00 76 DC 18 18 18 18 00 232 ш FC 30 78 CC CC 78 30 FC 233 щ 38 6C C6 FE C6 6C 38 00 234 ъ 38 6C C6 C6 6C 6C EE 00 235 ы 1C 30 18 7C CC CC 78 00 236 ь 00 00 7E DB DB 7E 00 00 237 э 06 0C 7E DB DB 7E 60 C0 238 ю 38 60 C0 F8 C0 60 38 00 239 я 78 CC CC CC CC CC CC 00 240 Ё 00 FC 00 FC 00 FC 00 00 241 ё 30 30 FC 30 30 00 FC 00 242 т 60 30 18 30 60 00 FC 00 243 у 18 30 60 30 18 00 FC 00 244 ф 0E 1B 1B 18 18 18 18 18 245 х 18 18 18 18 18 D8 D8 70 246 ц 30 30 00 FC 00 30 30 00 247 ч 00 76 DC 00 76 DC 00 00 248 ш 38 6C 6C 38 00 00 00 00 249 щ 00 00 00 18 18 00 00 00 250 ъ 00 00 00 00 18 00 00 00 251 ы 0F 0C 0C 0C EC 6C 3C 1C 252 ь 78 6C 6C 6C 6C 00 00 00 253 э 70 18 30 60 78 00 00 00 254 ю 00 00 3C 3C 3C 3C 00 00 255 00 00 00 00 00 00 00 00 Раздел 4. Вывод точечной графики. Цветной графический адаптор имеет три графических режима, PCjr - шесть, а EGA - семь. Как устанавливать эти режимы показано в [4.1.2]. Требования к размеру памяти существенно отличаются для различных режимов, в зависимости от разрешения экрана и числа используемых цветов. В своих улучшенных графических режимах EGA использует память дисплея совсем по-другому, чем остальные видео- системы, но он точно эмулирует их использование памяти при работе в трех общих режимах. Сначала рассмотрим цветной адаптор и систему PCjr. Два цвета (черный и белый) требуют только один бит памяти для каждой точки на экране. Четыре цвета занимают 2 бита, а 16 цветов - 4 (8-цвет- ные режимы не используются, поскольку три бита, требующиеся для их представления нельзя удобно разместить в 8 бит байта). Для всех режимов по вертикали имеется 200 точек. Низкое разрешение (используемое только на PCjr) использует 160 точек по горизонта- ли, среднее разрешение - вдвое больше (320 точек) и высокое раз- решение - еще вдвое больше (640 точек). Число килобайт памяти, требуемое для каждого режтима приведено в [4.5.3]. В двух- и четырехцветном режимах PCjr имеет выбор любого из 16 доступных цветов. Цветной адаптор более ограничен. В двухцветном режиме он всегда ограничен белым и черным, а в четырехцветном режиме только цвет фона может выбираться из 16 цветов, в то время как основной цвет должен браться только из двух предопределенных палетт. Палетта 0 содержит коричневый, зеленый и красный цвета, а палетта 1 - циан, магента и белый. В отличие от текстовых данных в режимах 4-6 и 8-A графические данные разбиты на видеостранице на части. В большинстве режимов данные разбиваются на две части, при этом первая половина буфера содержит данные для четных строк экрана, а вторая половина - данные для нечетных строк (строки нумеруются, начиная с верха экрана вниз). Однако в 16-цветных режимах PCjr буфер размером 32K делится на четыре части, каждая из которых содержит данные для каждой четвертой строки. В 4-цветных режимах первый байт буфера содержит информацию о самых левых точках строки 0, причем старший бит относится к самой левой точке. Следующий байт содержит информацию о следующем сег- менте строки и т.д. Для всей строки требуется 80 байт. 81-й байт содержит информацию о левом конце строки 2. В 16-цветных режимах картина приблизительно такая же, но для каждой строки требуется 160 байт и каждая часть буфера содержит данные только для вдвое меньшего числа строк. Для цветного графического адаптора четные строки занимают память со смещениями от 0000 до 1F3FH, а нечетные - от 2000H до 3F3FH. Промежуток между 1F3FH и 2000H игнорируется. Для PCjr соответствующие ячейки могут существенно различаться, в зависимости от режима и числа используемых страниц. PCjr спе- циально устроен таким образом, что вывод в 16K, начинающихся с сегмента B800H перенаправляется в ту область памяти, где реально расположен видеобуфер. Это свойство позволяет писать программы, которые будут одинаково работать на цветном дисплее и PCjr. Для режимов экрана EGA от DH до 10H память организована совсем по-другому. Она разделяется на одну, две или четыре битовые плос- кости, каждая из которых организована так же, как для черно-бело- го режима высокого разрешения, описанного выше: когда байт данных посылается в определенный адрес видеобуфера, то каждый бит соот- ветствует точке на экране, причем они описывают горизонтальный сегмент строки и бит 7 соответствует самой левой точке. Записы- ваются четыре таких битовых плоскости, соответствующих одним и тем же адресам в видеобуфере. Это отводит каждой точке 4 бита, что позволяет описывать 16 цветов. На рис. 4-4 показаны различные схемы распределения памяти. В графическом режиме могут выводиться и символы. Однако они создаются не обчыным способом, вместо этого BIOS вырисовывает их поточечно, не изменяя фонового цвета. По этой причине такие вещи как негативное изображение и мигание символов недоступны в графи- ческом режиме. Не выводится и курсор. BIOS может читать и опреде- лять установку точек в позиции курсора, чтобы узнать какой символ там содержится. Символы располагаются в одной из позиций, соот- ветствующих обычным строкам и столбцам, что означает, что они всегда начинаются на границе кратной восьми точкам. 4.4.1 Установка цветов для точечной графики. PCjr и EGA работают с цветом совсем по-другому, чем цветной адаптор. Они используют регистры палетты, которые позволяют в любой момент изменить цвет, который соответствует данному коду цвета. Вследствие этой разницы мы будем обсуждать эти две системы отдельно и начнем с цветного адаптора. Обе системы используют один и тот же основной набор кодов цвета, который в точности совпадает с используемым в текстовых режимах: Номер кода Цепочка битов Цвет 0 0000 черный 1 0001 синий 2 0010 зеленый 3 0011 циан 4 0100 красный 5 0101 магента 6 0110 коричневый 7 0111 белый 8 1000 серый 9 1001 яркосиний 10 1010 яркозеленый 11 1011 яркий циан 12 1100 розовый 13 1101 яркая магента 14 1110 желтый 15 1111 яркобелый Для цветного графического адаптора цвет разрешен только в режиме умеренного разрешения. Для каждой точки отводятся два бита каждого байта видеобуфера. Четыре возможных комбинации этих битов представляют один фоновый и три основных цвета. Фоновый цвет может быть любым из 16. Однако три основных цвета могут выбирать- ся из одной из двух палетт, каждая из которых содержит только три предопределенных цвета. Это следующие цвета: Номер кода Цепочка битов Палетта 0 Палетта 1 0 00 цвет фона цвет фона 1 01 зеленый циан 2 10 красный магента 3 11 желтый/коричневый белый Если Вы в какой-то момент переключились между палеттами, то все выведенные на экран цвета будут соответственно изменены. Единст- венный способ использовать цвет, не входящий в эти палетты, сос- тоит в том, чтобы искуственно рассматривать один из цветов палет- ты как фоновый цвет, что предполагает заполнение этим цветом всего экрана, когда экран чистится (используйте для этого прямое отображение в память). После этого истинный фоновый цвет может показываться "сквозь него" в качестве основного цвета. Такая техника приводит к созданию границы экрана, аналогичной той, что изображается в текстовых режимах. В противном случае граница экрана не может быть выделена цветом, так как весь экран закра- шивается фоновым цветом, хотя точки относящиеся к области границы нельзя адресовать. Отметим, что BIOS хранит в своей области дан- ных однобайтную переменную, которая содержит текущий номер палет- ты. Ее адрес равен 0040:0066H. Изменение этого числа не меняет текущую установку палетты; наоборот, если Вы измените цвет палет- ты другими средствами, помимо функций операционной системы, то значение этой переменной будет модифицировано. Символы могут перемешиваться с точечной графикой. Цвет, кото- рым будут выводиться символы, зависит от того, какую фукнцию Вы будете использовать для их вывода. Простейшая функция по умолча- нию использует третий цвет текущей палетты. Однако имеется ряд способов использовать любой из цветов палетты, а также выводить символы различными цветами. Смотрите обсуждение в [4.1.3]. EGA и PCjr обеспечивают добавочную гибкость в использовании атрибутов цвета, независимо от того, в каком режиме они работают. При 16-цветной графике четыре бита, находящиеся в памяти для каждой точки экрана дают цепочку битов, которая не переводится прямо в соответствующие цвета приведенной таблицы. Вместо этого каждый номер относится к одному из 16 регистров палетты. Каждый из этих регистров содержит цепочку битов, соответствующую цвету, который будет выводиться на самом деле. Если все 16 регистров будут содержать 0100, то независимо от того, какой атрибут будет приписан точке в памяти, она будет выведена красным цветом. Зна- чение в регистре 0 используется в качестве фонового цвета. На рис. 4-1 в [4.1.3] показан этот механизм. В двух- и четырехцвет- ном режимах используются только первые два или четыре регистра палетты. Регистры палетты позволяют программе изменить все выводимое в одном цвете на другой, не делая никаких изменений в видеобуфере. Более того отдельные объекты могут появляться и исчезать как по волшебству. Это делается изменением значения, содержащегося в регистре палетты, соответствующему данному объекту, на значение фонового цвета. Например, предположим, что фоновый цвет черный (0000) и что объект выведен с атрибутом 1110, так что он выводит- ся в том цвете, который указан в регистре палетты 15 (по умолча- нию значение для этого регистра желтый). Если изменить значение регистра 15 на 0000 (черный фоновый цвет), то объект исчезнет. Но на самом деле объект хранится в памяти, так как он записан с атрибутом 1110, а не с атрибутом 0000, как все точки фона. Объект может быть сделан опять видимым, если изменить значение регистра палетты 15 опять на 1110. Не обязательно, чтобы исчезали все желтые объекты, поскольку некоторые могут быть выведены с другим атрибутом, который также соответствует регистру палетты, содержа- щему также желтый цвет. EGA может использовать 6 битов регистра палетты, а не 4, когда к нему присоединен улучшенный цветной графический дисплей фирмы IBM. При этом становятся доступными 64 цвета, кодировка для кото- рых R'G'B'RGB. R, G и B соответствуют темным цветам, а R', G' и B' - светлым. Различные комбинации создают 64 оттенка. Как всег- да, 111111 соответствует белому цвету, а 000000 - черному. Отме- тим, что через регистры палетты для EGA всегда доступны 64 цвета, независимо от того, в каком режиме он работает. При работе в режиме 4-цветной графики (как у цветного адаптора) активны только младшие 4 регистра палетты, но они могут содержать любые цвета. Высокий уровень. Когда цветной дисплей работает в графическом режиме, то Бейсик обрабатывает оператор COLOR по другому, чем в текстовом режиме. Сначала идет фоновый цвет, в виде числа от 0 до 15, а затем идет номер палетты 0 или 1. Например, COLOR 2,1 устанавливает зеленый фоновый цвет (#2) для всего экрана и активизирует палетту 1. После этого три возможных основных цвета указываются их номерами в палетте: 1 - циан, 2 - магента и 3 - белый (сравните с операто- ром PAINT). Чтобы выключить цвет в режиме умеренного разрешения напишите SCREEN ,1. Отметим, что использование только черного и белого цветов в режиме умеренного разрешения не приводит к эко- номии памяти. PCjr использует оператор COLOR таким образом только в режиме SCREEN 1. Для режимов от SCREEN 3 до SCREEN 6 формат этого оператора COLOR основной,фоновый. При этом основной цвет - это число в диапазоне от 1 до 15 в 16-цветном режиме и от 1 до 3 - в 4-цветном. Он не должен быть равным 0, который всегда исполь- зуется в качестве фонового цвета. Имеются специальные операторы для установки регистров палетты: PALETTE и PALETTE USING. PALETTE устанавливает цвет соответствую- щий любому атрибуты. Например, PALETTE 9,11 приводит к тому, что точки нарисованные с цветом палетты 9 (обычно светлосиний) будут выведены в цвете 11 (светлый циан). Чтобы изменить установку всех регистров палетты к их первоначальному значению, т.е. чтобы ре- гистр 0 содержал 0, регистр 12 - 12 и т.д. надо написать просто PALETTE. Отметим, что в режимах SCREEN 4 и SCREEN 6 регистры палетты инициализируются таким образом, чтобы атрибуты цветов 1-3 были такими же, как для палетты 1 на цветном графическом дисплее. Это делается в целях совместимости. Все 16 регистров палетты могут быть установлены одним операто- ром PALETTE USING. PALETTE USING направляет содержимое 16-эле- ментного целого массива в регистры палетты. Имея несколько таких массивов программа может быстро переключать различные схемы цве- тов. Каждый элемент массива должен быть числом в диапазоне от 0 до 15, или -1, в последнем случае соответствующий регистр не изменяется. Например, для обращения привычной схемы цветов соз- дайте массив, в котором ARRAYNAME(0) = 15, ARRAYNAME(1) = 14 и т.д. Затем напишите PALETTE USING ARRAYNAME(0) и содержимое мас- сива ARRAYNAME будет передано в регистры палетты. 0 индицирует начальную позицию в массиве, с которой надо брать данные посылае- мые в регистры. Могут использоваться более длинные массивы, из которых данные могут браться начиная с любой точки, при условии что до конца массива еще есть 16 элементов. PALETTE USING ARRAY- NAME(12) будет брать данные, начиная с 12-го байта массива. Отме- тим, что оператор PALETTE USING работает как в текстовом, так и в графическом режимах. Вот пример: 100 DEF INT A-Z 'все переменные целые 110 DIM SCHEME1(16) 'массив для схемы цветов #1 120 DIM SCHEME2(16) 'массив для схемы цветов #2 130 DATA 3,5,9,2,4,12,15,1,6,7,14,13,8,11,10,0 140 DATA 0,11,13,7,1,12,2,5,10,8,14,6,15,4,9,3 150 FOR N = 0 TO 15 'для каждого регистра палетты 160 READ Q 'прочитать код цвета 170 SCHEME1(N) = Q 'и поместить его в массив 180 NEXT ' 190 FOR N = 0 TO 15 'то же самое со вторым массивом 200 READ Q ' 210 SCHEME2(N) = Q ' 220 NEXT ' 230 PALETTE USING SCHEME1(0) 'установка регистров . 500 PALETTE USING SCHEME2(0) 'меняем их посреди программы Средний уровень. Функция BH прерывания 10H устанавливает как фоновый цвет, так и цвета палетты - но не одновременно. Для установки фонового цвета надо поместить в BH 0, а затем код цвета от 0 до 15 в BL. Для установки палетты надо поместить в BH 1, а в BL 0 или 1. В данном примере устанавливается цвет фона циан и выбирается палет- та 0: ;---установка цвета фона и палетты MOV AH,0BH ;функция установки цвета MOV BH,0 ;сначала устанавливаем фоновый цвет MOV BL,3 ;код циана INT 10H ;установка цвета MOV BH,1 ;теперь устанавливаем палетту MOV BL,1 ;выбираем палетту 1 INT 10H ;устанавливаем палетту На PCjr эта функция работает точно так же в 4-цветном режиме, устанавливая регистры 1-3 в одну из схем цветов, используемых цветным адаптором. В 2-цветном режиме 0 в BL соответствует белому цвету, как цвету 1, а 1 - черному. Эта функция не влияет на наз- начения, используемые в 16-цветном режиме. Однако во всех случаях фоновый цвет может быть установлен засылкой в BH 0, а в BL - кода цвета. Низкий уровень. Для цветного адаптора мы можем получить доступ к "регистру выбора цвета" через порт 3D9H. В графических режимах этот регистр действует по-другому, чем в текстовых (описанных в [4.1.3]). Биты 0-3 содержат информацию о фоновом цвете в обычном формате (соот- ветственно синий, зеленый икрасный компоненты и интенсивность). Бит 5 выбирает палетту, когда этот бит равен 0, то палетта номер 0. В графических режимах остальные биты не имеют значения. Этот регистр только для записи, поэтому Вы должны указывать информацию и о фоновом цвете и о палетте, при изменении любого из них. MOV DX,3D9H ;адрес регистра выбора цвета MOV AL,00100110B ;цепочка битов для циана и палетты 1 OUT DX,AL ;посылаем ее Поскольку они используют регистры палетты, то этот пример неприменим ни к PCjr ни к EGA. Для них надо просто загрузить требуемые значения в эти регистры. У PCjr эти регистры нумеруются от 10H до 1FH. Доступ ко всем регистрам осуществляется через один порт с адресом 3DAH. Любое новое значение принимаемое этим портом воспринимается адресным регистром. Поэтому надо послать сначала номер регистра, а затем код цвета для этого регистра. Чтобы быть уверенным, что порт ожидает номер регистра надо прочитать из него. Например, чтобы поместить яркосиний цвет (1001) в регистр палетты 2: ;---помещаем код яркосинего цвета в регистр палетты 2 MOV DX,3DAH ;адрес массива ворот дисплея IN AL,DX ;читаем из него MOV AL,12H ;номер регистра OUT DX,AL ;посылаем номер регистра MOV AL,00001001B ;код яркосинего цвета OUT DX,AL ;посылаем цвет У EGA адрес порта доступа к регистрам палетты - 3C0H, а регистры нумеруются от 00 до 0FH. Надо прочитать из порта 3DAH (а не 3C0H), чтобы быть уверенным, что ожидается номер регистра. Когда к EGA присоединен улучшенный цветной дисплей и переключатели установлены соответствующим образом, то в регистры помещаются 6-битные значения. 4.4.2 Рисование точки на экране (монохромный, цветной и PCjr). Вследствие организации графической информации в видеобуфере вывод одной точки подразумевает изменение отдельных битов памяти. Режимы двух, четырех и шестнадцати цветов требуют, чтобы для установки характеристик одной точки были изменены один, два и четыре бита соответственно. Эти операции могут требовать огромно- го количества процессорного времени, о чем свидетельствует то, что большинство графического программного обеспечения работает очень медленно. Тщательное обдумывание часто позволяет сразу установить все биты одного байта, а не обращаться к одному и тому же байту 4 или 8 раз. Имейте это ввиду, и не следуйте слепо при- веденной здесь технике поточечного вывода. Высокий уровень. Бейсик предоставляет операторы PSET и PRESET для изменения цвета отдельной точки. Эти имена образованы от PointSET (установ- ка точки) и PointRESET (сброс точки). Они очень похожи. За обоими должны следовать координаты столбца и строки, указываемой точки, заключенные в скобки. Отметим, что координаты следуют в порядке x,y - т.е. сначала идет столбец, а затем строка; этот порядок обратный по отношению к порядку оператора LOCATE, который пози- ционирует текст на экране. PSET(50,80) или PRESET(50,80) устанав- ливают цвет точки в столбце 50 и строке 80. За оператором PSET может следовать код цвета, который лежит в диапазоне, определяе- мом текущим режимом экрана. Если код цвета не указан, то исполь- зуется максимальный номер кода, который допустим для данного режима. В PRESET цвет не указывается. Он всегда возвращает точке цвет фона (код 0). Например: 100 PSET(100,180),3 'установка цвета 3 текущей палетты 110 PRESET(100,180) 'изменение цвета точки на фоновый PSET и PRESET обычно используют систему координат, в которой левый верхний угол экрана имеет координаты 0,0. Оператор WINDOW позволяет Вам переопределить систему координат так, что например, координаты левого верхнего угла будут -100,100, центра экрана - 0,0, а правого нижнего угла - 100,-100. Для этого случая надо записать оператор в виде WINDOW(-100,100)-(100,-100). (Новые координаты не будут влиять на систему координат 25*80 (или 25*40), в которой оператор LOCATE позиционирует символы на графи- ческом экране [4.2.1].) Как и в операторе LINE [4.4.5], первое число каждой пары в скобках указывает горизонтальную координату (по оси x). Координа- ты могут быть как положительными, так и отрицательными, лишь бы они не были равными. Левому краю экрана всегда присваивается меньшее число (которое может быть большим отрицательным). Таким образом, даже если Вы поменяете координаты в примере и запишете оператор WINDOW(100,-100)-(-100,100), то значение -100 будет взято для левой границы экрана. Второе число каждой пары координат определяет границы экрана по вертикали. И опять, меньшее значение будет относиться к нижней границе экрана, независимо от того, в какой паре координат оно указано. Большее положительное значение (или меньшее из двух отрицательных) присваивается в качестве значения оси y для верх- ней строки экрана. Направление увеличения значений может быть обращено, с тем чтобы максимальные значения соответствовали низу экрана и наоборот. Надо просто добавить к оператору слово SCREEN, например, WINDOW SCREEN(-100,100)-(100,-100). Программа может указывать точки, относящиеся к области за пределами координат экрана. Например, центр окружности может находиться за пределами экрана, с тем чтобы видна была только часть дуги. Отметим, что координаты, указываемые оператором WIN- DOW могут непрерывно изменяться при изменении масштаба или угла зрения на объект. Изображение должно перерисовываться, а иногда стираться, при изменении координат окна. Оператор PMAP преобразует координаты от обычной физической системы координат к "мировой" системе, устанавливаемой оператором WINDOW. PMAP использует четыре кодовых номера: 0 преобразует x из "мировой" системы в физическую 1 преобразует y из "мировой" системы в физическую 2 преобразует x из физической системы в "мировую" 3 преобразует y из физической системы в "мировую" Оператор имеет форму PMAP(позиция,код). Например, предположим, что Вы установили систему "мировых" координат оператором WINDOW. Координаты левого верхнего угла экрана (-100,100), а правого нижнего - (100,-100). Какая будет позиция центральной точки экра- на (0,0) при использовании обычной физической системы 320*200, в которой левый верхний угол имеет координаты 0,0? Чтобы найти X напишите X = PMAP(0,0), а Y - напишите Y = PMAP(0,1). Вы получите значение X = 160, а Y = 100. Средний уровень. Функция CH прерывания 10H устанавливает точку. DX содержит строку, а CX - столбец, оба отсчитываемые от 0. Код цвета поме- щается в AL. Отметим, что содержимое AX будет разрушено при вы- полнении прерывания. Если Вы используете это прерывание в цикле, то не забудьте сохранить AX на стеке и каждый раз восстанавливать его. ;---вывод точки с координатами 100,180 MOV AH,0CH ;функция установки точки MOV AL,3 ;выбираем цвет 3 палетты MOV CX,100 ;строка MOV DX,180 ;столбец INT 10H ;выводим точку ;---стираем точку MOV AH,0CH ;восстанавливаем функцию MOV AL,0 ;используем для стирания фоновый цвет MOV DX,100 ;строка MOV CX,180 ;столбец INT 10H ;стираем точку В то время как цвет палетты помещается в младшие биты AL, старший бит также имеет значение. Если он равен 1, то над цветом производится операция исключающего ИЛИ с текущим цветом. Напом- ним, что операция исключающего ИЛИ устанавливает бит только в том случае если из двух сравниваемых битов установлен только один. Если оба сравниваемые бита равны 1 или оба равны 0, то результат будет 0. Для двухцветного режима это означает, что такая операция обращает установку бита. Если эту операцию применить ко всем точкам экрана, то будет обращен весь экран. В четырех- и 16-цвет- ном режимах, с другой стороны, области экрана могут менять свои цвета. Например, пусть в 4-цветном режиме умеренного разрешения область занята точками либо цвета 1 палетты (установка битов 01B) или цвета 2 палетты (10B). Что произойдет, если применить ко всем точкам этой области операцию исключающего ИЛИ с 11B? 01B перейдет в 10B, а 10B перейдет в 01B - цвета будут обращены. Низкий уровень. На низком уровне мы имеем возможность прямого доступа к видео- буферу (отображение в память). Сначала Вы должны вычислить смеще- ние точки (а) внутри буфера и (б) внутри байта, содержащего биты, относящиеся к данной точке. После этого битовые операции обеспе- чат соответствующую установку. Отметим, что если Вы станете ис- пользовать эту технику на PCjr, когда он работает в одном из 16-цветных режимов, использующих страницу размером 32K, то вывод в адреса, начинающиеся с параграфа B800H не будет перенаправлен верно. Вам необходимо прямо адресовать реальные ячейки, располо- женные в сегменте ниже 2000H. Для нахождения точки необходимо прежде всего определить нахо- дится ли она в четной или нечетной строке. В данном примере стро- ка помещена в CX, а столбец - в DX. Если бит 0 регистра CX равен 0, то строка имеет четный номер. Четные строки расположены со смещением 0 относительно начала буфера. Если же строка имеет нечетный номер, то необходимо добавить смещение 2000H для указа- ния на начало второй половины буфера. Затем разделите номер строки на 2, необходимо подсчитать число только четных или нечетных строк и умножьте результат на 80, т.к. на одну строку расходуется 80 байт. Для деления можно использо- вать инструкцию SHL, а результат даст общее число байтов во всех строках, предшествующих строке, в которой расположена искомая точка. Вместо того, чтобы затем вычислять число столбцов в текущей строке, лучше сначала определить позицию пары битов в байте, которые содержат эту точку. Это достигается обращением всех битов в номере столбца (после того как сохранена его копия) и выделения двух младших битов. Эта процедура покажет находятся ли два бита, относящиеся к точке на первой, второй, третьей или четвертой позиции в байте. Умножив это значение на 2 мы получаем номер в байте первого из двух битов, относящихся к данной точке. Затем приходит время подсчитать число байтов в строке, пред- шествующих байту, содержащему итнформацию о требуемой точке. Для режима умеренного разрешения надо разделить число столбцов на 4, а для высокого разрешения - на 8. После этого надо сложить три смещения: смещение за счет номера строки, за счет номера столбца и смещение начала четных/нечетных строк в буфере. После этого Вы можете получить требуемый байт из буфера. Наконец, надо произвести операцию над соответствующими битами байта. Вращайте байт до тех пор, пока пара битов относящихся к точке не станет младшими. При вращении необходимо использовать ранее подсчитанное значение позиции битов. Затем выключите оба бита поместите в них инструкцией OR требуемый код палетты. Затем надо произвести обратное вращение и послать байт обратно в буфер. ;---в сегменте данных PALETTE_COLOR DB 2 ;---вызов процедуры MOV AX,0B800H ;указываем на видеобуфер MOV ES,AX ; MOV CX,100 ;номер строки MOV DX,180 ;номер столбца CALL SET_DOT ; . . ;---определяем число байтов в предшествующих строках SET_DOT PROC TEST CL,1 ;номер строки нечетный? JZ EVEN_ROW ;если нет, то вперед MOV BX,2000H ;смещение для нечетных строк JMP SHORT CONTINUE ;переход вперед EVEN_ROW: MOV BX,0 ;смещение для четных строк CONTINUE: SHR CX,1 ;делим число строк на 2 MOV AL,80 ;умножаем на 80 MUL CL ;в AX - число байтов ;---определяем положение пары бит в байте MOV CX,DX ;копируем номер столбца NOT CL ;обращаем биты AND CL,00000011B ;в CL - позиция битов (0-3) SHL CL,1 ;позиция первого бита пары ;---подсчитываем смещение столбца в байтах SHR DX,1 ;делим номер столбца на 4 SHR DX,1 ;(нужны два младших бита) ;---вычисляем смещение для изменяемого байта ADD AX,DX ;складываем все три смещения ADD BX,AX ; ;---изменяем биты нужного байта MOV AH,ES:[BX] ;читаем нужный байт ROR AH,CL ;сдвигаем нужные биты вниз AND AH,11111100B ;чистим младшие 2 бита MOV AL,PALETTE_COLOR ;изменяем их на цвет палетты OR AH,AL ; ROL AH,CL ;обратное вращение MOV ES:[BX],AH ;возвращаем байт RET ; SET_DOT ENDP 4.4.3 Рисование точки на экране (EGA). У EGA графика более сложная. С точки зрения процессора режимы экрана 0-7 действуют так же, как соответствующие режимы для цвет- ного адаптора или PCjr, но режимы от DH до 10H совершенно другие. Организация памяти для этих режимов меняется, в зависимости от числа используемых цветов и количества памяти, имеющейся на плате дисплея. Смотрите рис. 4-4 в [4.4.0]. В режимах D, E и 10H память разбита на 4 битовые плоскости. Каждая плоскость организована таким же образом, как для черно-бе- лого режима высокого разрешения цветного адаптора, который обсуж- дался в [4.4.2]: когда байт данных посылается в определенный адрес видеобуфера, то каждый бит соответствует точке на экране, причем весь байт соответствует горизонтальному сегменту линии, а бит 7 соответствует самой левой точке. Выводятся четыре таких битовых плоскости, относящиеся к одним и тем же адресам в видео- буфере. Это приводит к тому, что каждая точка описывается четырь- мя битами (давая 16 цветов), причем каждый бит находится вотдель- ном байте отдельной битовой плоскости. Но как Вы можете записать 4 различных байта данных, располо- женных по одному и тому же адресу? Ответ на этот вопрос состоит в том, что Вы не посылаете последовательно четыре байта по этому адресу. Вместо этого один из трех режимов записи позволяет изме- нить все 4 байта, на основании одного байта данных полученного от процессора. Влияние данных посланных процессором зависит от уста- новки нескольких регистров, включающих два регистра маски, кото- рые определяют на какие биты и в каких битовых плоскостях будут изменяться биты. Для понимания этих регистров мы должны сначала разобраться с четырьмя регистрами задвижки (latch register). Они содержат дан- ные для четырех битовых плоскостей в той позиции, к которой было последнее обращение. (Заметим, что термин битовая плоскость ис- пользуется как для целой области видеобуфера, так и для однобайт- ного буфера, временно хранящегося в регистре задвижки.) Когда процессор посылает данные по определенному адресу, то эти данные могут изменить или полностью сменить данные регистра задвижки, а впоследствии именно данные из регистра задвижки записываются в видеобуфер. Каким образом данные процессора влияют на регистр задвижки зависит от используемого режима записи, а также от уста- новки некоторых других регистров. При чтении адреса из видеобуфе- ра регистры задвижки заполняются четырьмя байтами из четырех битовых плоскостей по данному адресу. Регистрами задвижки легко манипулировать, производя их содержимым различные логические операции, что позволяет устраивать различные графические трюки. Регистр маски битов и регистр маски карты действуют на регист- ры задвижки, защищая определенные биты или битовые плоскости от изменения под действием данных, поступающих от процессора. Ре- гистр маски битов это регистр только для записи, адрес порта которого 3CFH. Сначала надо послать 8 в порт 3CEH, чтобы указать на этот регистр. Установка бита этого регистра в 1 маскирует этот бит во всех четырех битовых плоскостях, делая соответствующую точку недоступной для изменения. Однако, поскольку оборудование работает в байтовых терминах, то реально "неизменяемые" биты перезаписываются в четыре битовые плоскости. Данные для этих маскируемых битов хранятся в регистрах задвижки, поэтому програм- ма должна быть уверена, что текущее содержимое регистров задвижки относится к правильному адресу памяти. По этой причине перед записью по данному адресу надо считывать из него. Регистр маски карты имеет адрес порта 3C5H. Этот регистр толь- ко для записи. Перед посылкой данных надо послать по этому адресу 2 как указатель. Биты 0-3 этого регистра соответствуют битовым плоскостям 0-3; старшие 4 бита регистра не используются. Когда биты 0-3 равны 0, то сответствующие битовые плоскости не изме- няются при операциях записи. Это свойство используется по-разному в различных режимах записи, как Вы увидите в дальнейшем. Три режима записи устанавливаются регистром режима, который является регистром только для записи, а адрес порта для него 3CFH, который индексируется предварительной засылкой 5 в этот порт. Режим записи устанавливается в битах 0 и 1, как число от 0 до 2. Бит 2 должен быть равным 0, так же как и биты 4-7. Бит 3 устанавливает один из двух режимов чтения из видеобуфера. Этот бит может быть 0 или 1. BIOS EGA устанавливает режим записи в 00. Режим записи 0: В простейшем случае режим записи 0 копирует данные процессора в каждую из четырех битовых плоскостей. Например, пусть по опре- деленному адресу видеобуфера послано 11111111B и разрешены все биты и все битовые плоскости (т.е. ничто не маскировано описанны- ми выше регистрами масок). Тогда каждый бит во всех четырех плос- костях будет установлен в 1, так что цепочка битов для каждой из соответствующих точек будет 1111B. Это означает, что 8 точек будут выведены в цвете 15, который изначально соответствует ярко- белому цвету, хотя регистры палетты позволяют, чтобы на самом деле это был любой из допустимых цветов. Теперь рассмотрим тот же случай, но посылается значение 00001000B. Цепочка битов для точки 3 будет 1111, а для остальных - 0000, что соответствует черному (изначально). Поэтому в данном случае только точка 3 появится на экране (яркобелая), а остальные 7 точек будут выключены. Даже если остальные 7 точек перед этим выводились в каком-то цвете, то теперь все они будут переключены на 0000. Теперь рассмотрим другие цвета, кроме 1111B. Если Вы пошлете код палетты желаемого цвета в регистр маски карты, то регистр маскирует определенные битовые плоскости таким образом, что будет воспроизведен требуемый цвет. Например, если Вы хотите цвет с кодом 0100, то пошлите 0100 в регистр маски карты. Тогда битовые плоскости 0, 1 и 3 не будут изменяться. Когда Вы пошлете по нуж- ному адресу 11111111B, то это значение будет помещено только в битовую плоскость 2 и цепочка битов для каждой точки будет 0100. Если Вы пошлете по этому адресу 00001000B, то точка 3 будет иметь цепочку битов 0100, а остальные точки - 0000. Имеется, однако, одна сложность. Регистр маски карты запрещает изменение битовых плоскостей, но не обнуляет их. Предположим, что битовая плоскость 0 была заполнена единицами, а битовые плоскости 1 и 3 были заполнены нулями. Если Вы запретите изменения в этих трех плоскостях, а затем пошлете 11111111B по определенному адре- су, то битовая плоскость 2 будет заполнена 11111111B, а битовая плоскость 0 сохранит свои единицы, поэтому результирующий код цвета каждой точки станет 0101B. Встречаются случаи, когда это свойство можно использовать для изменения цветов экрана. Но вооб- ще говоря, необходимо очищать все четыре битовые плоскости (т.е. все четыре регистра задвижки) перед тем, как писать туда любые цвета кроме 1111B или 0000B. Это делается просто посылкой 0 по указанному адресу. Необходимо чтобы при этом была разрешена за- пись во все четыре битовые плоскости. Вышеприведенное обсуждение касалось одновременного вывода восьми точек. Ну а как вывести меньшее количество точек? В этом случае, конечно, необходимо сохранить существующие данные для некоторых точек, а чтобы это было возможно текущее содержимое данного адреса сохраняется в регистрах задвижки. Затем исполь- зуется регистр маски битов для маскирования тех точек, которые не должны изменяться. Если бит этого регистра сброшен в 0, то данные получаемые от процессора для этого бита игнорируются и вместо них используются данные, хранящиеся в регистрах задвижки. Равен ли этот бит в данных процессора 0 или 1 - не имеет значения; если Вы изменяете только бит 2, а все остальные маскированы, то данные, которые приходят от процессора могут быть 0FFH или 4H, или любое другое значение, для которого бит 2 установлен. Если бит 2 сьро- шен, то 0 помещается в этой позиции во всех разрешенных битовых плоскостях. Вообще говоря, программа должна сначала прочитать любую ячей- ку, в которую она собирается записать меньше чем 8 точек. Имеются два режима чтения (обсуждаемые в [4.4.4]) и безразлично какой из них выбран. Операция чтения загружает регистры задвижки четырьмя байтами данных для данного адреса памяти. Данные, возвращаемые процессору операцией чтения, могут быть отброшены. До сих пор были рассмотрены самые простые возможности режима записи 0. При желании Вы можете делать намного более сложные манипуляции. Одна из возможностей состоит в модификации регистров задвижки с помощью логических операций перед записью. Для реали- зации этой возможности регистр вращения данных использует следую- щие биты: биты 2-0 число вращений 4-3 00 данные не модифицируются 01 логическое И с регистром задвижки 10 логическое ИЛИ с регистром задвижки 11 исключающее ИЛИ с регистром задвижки 7-5 не используются Число вращений, которое может быть от 0 до 7, показывает сколько битов данных должны вращаться перед тем, как поместить их в регистр задвижки. Обычно это значение равно нулю. Аналогично, биты 4-3, как правило равны 00, кроме случаев, когда производятся логические операции. За счет манипуляций с этим регистром одни и те же данные могут давать различные цвета и изображения без до- полнительной процессорной обработки. Регистр вращения данных индексируется посылкой 3 в порт 3CEH; затем данные посылаются в 3CFH. Наконец, режим записи 0 может работать совсем по-другому если разрешены установка/сброс. В этом случае определенные цвета в младших четырех битах регистра установки/сброса (который тоже имеет адрес порта 3CFH, а индексируется посылкой 0 в 3CEH). Име- ется соответствующий регистр разрешения установки/сброса, который разрешает любой из этих четырех битов, устанавливая свои младшие биты в 1. Когда все 4 бита в регистре установки/сброса разрешены, то они помещаются во все 8 адресов битовой плоскости при получе- нии данных от процессора, при этом сами данные процессора отбра- сываются. Если разрешены не все биты установки/сброса, то данные процессора помещаются для запрещенных точек. Отметим, что регистр маски битов запрещает запись данных установки/сброса в определен- ные точки, но установка регистра маски карты игнорируется при использовании установки/сброса. BIOS инициализирует регистр раз- решения установки/сброса в 0, так что он неактивен. Его адрес порта 3CFH, а индексируется он посылкой 1 в порт 3CEH. Режим записи 1: Режим записи 1 предназначен для специальных приложений. В этом режиме текущее содержимое регистра задвижки записывается по ука- занному адресу. Напоминаем, что регистры задвижки заполняются операцией чтения. Этот режим очень полезен для быстрого переноса данных при операциях сдвига экрана. Регистр маски битов и регистр маски карты не влияют на эту операцию. Не имеет также значения какие данные посылает процессор - содержимое регистров задвижки записывается в память без изменений. Режим записи 2: Режим записи 2 предоставляет альтернативный способ установки отдельных точек. Процессор посылает данные, у которых имеют зна- чение только 4 младших бита, которые рассматриваются как цвет (индекс регистра палетты). Можно сказать, что эта цепочка битов вставляется поперек битовых плоскостей. Цепочка дублируется на все восемь точек, относящихся к данному адресу, до тех пор пока регистр маски битов не предохраняет определенные точки от измене- ния. Регистр маски карты активен, как и в режиме записи 0. Конеч- но процессор должен послать полный байт, но только младшие 4 бита существенны. Высокий уровень. Бейсик поддерживает EGA в традиционных режимах цветного графи- ческого адаптора. Ко времени выхода этой книги поддержки дополни- тельных режимов EGA не существовало. Поэтому у Вас нет другого выхода, кроме как использовать прямое отображение в видеобуфер, который начинается с адреса A000:0000. Самая тяжелая проблема состоит в установке режима дисплея. Для ее решения используйте следующую процедуру на машинном языке: 10 S$ = CHR$(&H2A)+CHR$(&HE4)+CHR$(&HB0)+CHR$(&H0D) +CHR$(&HCD)+CHR$(&H10)+CHR$(&HCB) 20 DEF SEG 'установка сегмента 30 Y = VARPTR(S$) 'указатель на строку 40 Z = PEEK(Y+1)+PEEK(Y+2)*256 'вычисление адреса строки 50 CALL Z 'вызов процедуры Четвертый байт S$ содержит номер режима, в данном случае режим D. Вы можете выбрать другой режим. В приложении Г объясняется как эта процедура работает в Бейсике. Она полностью завершенная, не нужно никакой побочной памяти, в которой содержался бы машинный код. Не забудьте восстановить режим дисплея после завершения своих манипуляций. Затем надо установить соответствующий режим записи. Вот как устанавливается режим записи 2: 50 OUT &H3CE,5 'индексируем регистр режима записи 60 OUT &H3CF,2 'выбираем режим 2 Режим записи также должен быть восстановлен после завершения программы. Наконец, приведем образцы кода, реализующие прямое отображение в видеобуфер: Режим записи 0: 100 'рисуем красную точку в левом верхнем углу экрана 110 DEF SEG = &HA000 'указываем на видеобуфер 120 OUT &H3CE,8 'адресуем регистр маски битов 130 OUT &H3CF,128 'маскируем все биты, кроме седьмого 140 X = PEEK(0) 'читаем текущее значение в задвижку 150 POKE 0,0 'чистим 160 OUT &H3C4,2 'адресуем регистр маски карты 170 OUT &H3C5,4 'устанавливаем красный цвет 180 POKE 0,&HFF 'рисуем точку Режим записи 1: 100 'копируем верхнюю строчку точек в следующую 110 DEF SEG = &HA000 'указываем на видеобуфер 120 FOR N = 0 TO 79 'для всех 80 байтов строки 130 X = PEEK(N) 'заполняем задвижки 140 POKE N+80,Y 'копируем в следующую строку 150 NEXT 'переходим к следующему сегменту Режим записи 2: 100 'рисуем красную точку в левом верхнем углу экрана 110 DEF SEG = &HA000 'указываем на видеобуфер 120 OUT &H3CE,8 'адресуем регистр маски битов 130 OUT &H3CF,128 'маскируем все биты, кроме седьмого 140 X = PEEK(0) 'читаем текущее значение в задвижку 150 POKE 0,4 'посылаем красный цвет Средний уровень. EGA поддерживает стандартные графические функции BIOS. Можно вывести точку с помощью функции CH прерывания 10H, так же как для цветного дисплея или PCjr. При входе DX должен содержать номер строки, а CX - номер столбца, и то и другое отсчитывается от 0. Код цвета помещается в AL. Содержимое AX меняется при выполнении прерывания. ;---рисуем точку по адресу 50,100 MOV AH,0CH ;функция вывода точки MOV AL,12 ;выбираем регистр палетты 12 MOV CX,100 ;номер строки MOV DX,50 ;номер столбца INT 10H ;рисуем точку Низкий уровень. Ниже приведены примеры для трех режимов записи. Перед их ис- пользованием необходимо установить режим дисплея, использующий видеобуфер с адреса A000:0000. Для этого можно использовать стан- дартную функцию BIOS, например, для установки режима D: MOV AH,0 ;функция установки режима MOV AL,0DH ;выбираем режим D INT 10H ;устанавливаем режим Не забудьте восстановить режим перед завершением программы. Кроме того, Вам необходимо установить требуемый режим записи. Вот при- мер установки режима записи 2: MOV DX,3CEH ;указываем на регистр адреса MOV AL,5 ;инедксируем регистр 5 OUT DX,AL ;посылаем индекс INC DX ;указываем на регистр режима MOV AL,2 ;выбираем режим записи 2 OUT DX,AL ;устанавливаем режим И, наконец, примеры трех режимов записи: Режим записи 0: ;---рисуем красную точку в левом верхнем углу экрана MOV AX,0A000H ;указываем на видеобуфер MOV ES,AX ; MOV BX,0 ;указываем на первый байт буфера ;---маскируем все биты, кроме седьмого MOV DX,3CEH ;указываем на адресный регистр MOV AL,8 ;номер регистра OUT DX,AL ;посылаем его INC DX ;указываем на регистр данных MOV AL,10000000B ;маска OUT DX,AL ;посылаем данные ;---чистим текущее содержимое задвижки MOV AL,ES:[BX] ;читаем содержимое в задвижку MOV AL,0 ;готовимся к очистке MOV ES:[BX],AL ;чистим задвижку ;---установка регистра маски карты для красного цвета MOV DX,3C4H ;указываем на адресный регистр MOV AL,2 ;индекс регистра маски карты OUT DX,AL ;установка адреса INC DX ;указываем на регистр данных MOV AL,4 ;код цвета OUT DX,AL ;посылаем код цвета ;---рисуем точку MOV AL,0FFH ;любое значение с установленным 7 битом MOV ES:[BX],AL ;выводим точку Режим записи 1: ;---копируем строку в следующую строку MOV CX,80 ;число байтов в строке MOV BX,0 ;начинаем с 1-го байта буфера MOV AX,0A000H ;адрес буфера MOV ES,AX ; NEXT_BYTE: MOV AL,ES:[BX] ;заполняем задвижку MOV ES:[BX]+80,AL ;выводим в следующую строку INC BX ;переходим к следующему байту LOOP NEXT_BYTE ; Режим записи 2: ;---рисуем красную точку в левом верхнем углу экрана MOV AX,0A000H ;адрес буфера MOV ES,AX ; MOV BX,0 ;указываем на первый байт буфера ;---установка регистра маски битов MOV DX,3CEH ;указываем на адресный регистр MOV AL,8 ;регистр маски битов OUT DX,AL ;адресуем регистр INC DX ;указываем на регистр данных MOV AL,10000000B ;маскируем все биты, кроме 7-го OUT DX,AL ;посылаем данные ;---рисуем красную точку MOV AL,ES:[BX] ;заполняем регистры задвижки MOV AL,4 ;красный цвет MOV ES:[BX],AL ;рисуем точку 4.4.4 Определение цвета точки экрана. Для графических режимов цветного адаптора или PCjr определение цвета точки на низком уровне состоит в обращении процедуры вывода точки: программа читает из видеобуфера и выделяет интересующие биты. Однако для EGA этот метод непригоден, поскольку в режимах DH - 10H каждому адресу памяти соответствует два или четыре бай- та. EGA имеет два режима чтения, чтобы преодолеть эту трудность. Имейте ввиду, что для PCjr и EGA, после того, как Вы определили код цвета точки, необходимо еще проверить установку текущего ре- гистра палетты для этого кода, чтобы определить какой цвет ему приписан. Любой язык программирования имеет доступ к двум режимам чтения EGA. В режиме 0 возвращается байт, содержащийся во всех четырех битовых плоскостях, по указанному адресу. Режим 1 ищет указанный код цвета и возвращает байт, в котором бит установлен в 1, когда соответствующая точка имеет данный цвет. Бит 3 регистра режима определяет какой режим чтения установлен (0 = режим 0). Доступ к этому регистру осуществляется через порт 3CFH и Вы должны предва- рительно послать 5 в порт 3CEH, чтобы выбрать этот регистр. Обыч- но все остальные биты этого регистра, который можно только пи- сать, сброшены в 0, кроме битов 0 и 1, которые определяют режим записи. Поскольку при инициализации BIOS устанавливает эти биты в режим записи 0 (так что они оба равны 0), то обычно Вам нужно просто послать в этот регистр 0, чтобы установить режим чтения 0 и послать 8, чтобы установить режим чтения 1. Режим чтения 0 требует, чтобы Вы предварительно установили регистр выбора карты. Единственная задача этого регистра - уста- новить, какая из карт битов должна быть прочитана. Поэтому в него надо послать число от 0 до 3. Этот регистр имеет адрес порта 3CFH и надо предварительно послать 4 в порт 3CEH, чтобы указать этот регистр. Режим чтения 1 более сложен. Сначала регистр сравнения цветов должен быть заполнен цепочкой битов для кода цвета, который Вы ищете. Этот код помещается в младшие 4 бита регистра; старшие 4 бита - несущественны. Этот регистр имеет адрес порта 3CFHи указы- вается предварительной засылкой 2 в порт 3CEH. После чтения ячей- ки памяти возвращается байт, который имеет биты установленные в 1 для каждой точки, имеющей нужный цвет. Однако за счет использова- ния регистра безразличия цвета (color don't care register) один или более битов кода цвета могут при сравнении игнорироваться. Обычно 4 младших бита этого регистра установлены в 1; обнуление одного из этих битов приведет к тому, что содержимое соответст- вующей битовой плоскости будет игнорироваться. Например, если цепочка битов для точки 3 (бит 3) по указанному адресу равна 0110 и регистр сравнения цветов содержит значение 0010, то при сравне- нии будет возвращен байт, у которого бит 3 равен 0, если в ре- гистре безразличия цветов все биты равны 1. Но если регистр без- различия цветов содержит 1011, то в байте, возвращаемом процессо- ру бит 3 будет равен 1. Регистр безразличия цветов имеет адрес порта 3CFH и индекси- руется засылкой 7 в порт 3CEH. Старшие 4 его бита не играют ника- кой роли. Отметим, что документация IBM (от 2 августа 1984 г.) утверждает что регистр действует обратным образом, т.е., что 1 в регистре заставляет операцию сравнения игнорировать соответствую- щую битовую плоскость. Эксперимент показывает обратное. Ни один из этих двух режимов чтения не может дать быстрый ответ на вопрос о цвете определенной точки. В режиме чтения 0 необходимы 4 отдельных чтения, по одному для каждой битовой плос- кости, после чего надо еще выделить соответствующие биты из каж- дого байта. В режиме чтения 1, с другой стороны, может потребо- ваться до 16 чтений, прежде чем для требуемой точки будет возвра- щен установленный бит, указывающий что эта точка имеет данный цвет. Но хотя EGA относительно медленно выполняет данную задачу, зато для других целей он работает очень быстро. Высокий уровень. Бейсик предоставляет функцию POINT, которая возвращает цвет точки. Цвет палетты точки, находящейся в столбце 200 и строке 100 находится путем Q = POINT(200,100). Значение, возвращаемое в Q - это обычный кодовый номер цвета. Если указана точка, находящаяся за пределами экрана, то функция POINT возвращает значение -1. Когда координатная система экрана изменяется оператором WINDOW [4.4.2], то функция POINT переходит к новой системе. POINT может также сообщить позицию последней выведенной точки. При использовании обычной координатной системы, в которой 0,0 соответствует левому верхнему углу экрана, Q = POINT(1) возвра- щает в Q x-координату точки, а Q = POINT(2) - y-координату. Если действует оператор WINDOW, то Q = POINT(3) и Q = POINT(4) возвра- щает x- и y-координаты в новой системе. Когда нет активного опе- ратора WINDOW, то последние два оператора действуют так же, как и первые два. К моменту выхода этой книги Бейсик не поддерживал улучшенные графические режимы EGA (D-10H). В этих режимах программа должна прямо читать содержимое видеобуфера. Вот пример использования режима чтения 1 для поиска кодов цветов 0001 и 1001: 100 OUT &H3CE,5 'адрес регистра режима 110 OUT &H3CF,8 'устанавливаем режим чтения 0 120 OUT &H3CE,2 'адрес регистра сравнения цветов 130 OUT &H3CF,1 'ищем цвет 0001 140 OUT &H3CE,7 'адрес регистра безразличия цветов 150 OUT &H3CF,7 '7 = 0111B, поэтому м. б. 0001 и 1001 160 DEF SEG = &HA000 'адрес видеобуфера для EGA 170 X = PEEK(0) 'читаем первый байт 180 IF X <> 0 THEN... '..то цвет 0001 или 1001 найден Средний уровень. Функция D прерывания 10H возвращает код цвета указанной точки. BIOS имеющийся на плате EGA обеспечивает, что эта функция рабо- тает в любом режиме дисплея. Надо поместить номер строки (отсчи- тываемый от 0) в DX, а номер столбца (также отсчитываемый от 0) - в CX. Результат возвращается в AL. ;---определяем код палетты точки 100,200 MOV AH,0DH ;номер функции чтения цвета точки MOV DX,100 ;номер строки MOV CX,200 ;номер столбца INT 10H ;теперь код цвета в AL Низкий уровень. Для графических режимов цветного адаптора и PCjr надо просто обратить процесс прямого отображения в память, которым устанавли- вается цвет точки, как показано в [4.4.2]. Можно испоьзовать приведенный там пример, который надо завершить следующим кодом: ;---изменение битов (место для вставки изменений) MOV AH,ES:[BX] ;берем байт из нужной позиции ROR AH,CL ;сдвигаем 2 нужных бита вниз AND AH,00000011B ;выключаем остальные биты RET ;теперь в AH - код палетты Для режимов EGA от DH до 10H надо пользоваться регистрами, которые были описаны выше. В следующем примере режим чтения 0 испоьзуется для чтения битовой плоскости 2 по адресу A000:0012. ;---установка режима чтения MOV DX,3CEH ;индексный регистр MOV AL,5 ;сначала адресуем регистр режима OUT DX,AL ;посылаем индекс INC DX ;указываем на сам регистр MOV AL,0 ;устанавливаем режим чтения 0 OUT DX,AL ; ;---установка битовой плоскости, которую будем читать DEC DX ;назад к индексному регистру MOV AL,4 ;адрес регистра выбора карты OUT DX,AL ;посылаем индекс INC DX ;указываем на сам регистр MOV AL,2 ;запрос битовой плоскости 2 OUT DX,AL ;посылаем значение ;---чтение битовой плоскости MOV AX,0A000H ;адрес видеобуфера MOV ES,AX ; MOV BX,12 ;смещение в буфере MOV AL,ES:[BX] ;читаем из битовой плоскости 2 И, наконец, пример поиска кодов цвета 0010 и 1010 с использова- нием режима чтения 1: ;---установка режима чтения MOV DX,3CEH ;регистр индекса MOV AL,5 ;адресуем сначала регистр режима OUT DX,AL ;посылаем индекс INC DX ;указываем на сам регистр MOV AL,8 ;устанавливаем бит 3 для режима 1 OUT DX,AL ;устанавливаем режим ;---установка регистра сравнения цветов DEC DX ;возвращаемся к индексному регистру MOV AL,2 ;адрес регистра сравнения цветов OUT DX,AL ;посылаем индекс INC DX ;указываем на сам регистр MOV AL,0010B ;код цвета OUT DX,AL ;посылаем код ;---установка регистра безразличия цветов DEC DX ;возвращаемся к индексному регистру MOV AL,7 ;адрес регистра безразличия цветов OUT DX,AL ;посылаем индекс INC DX ;указываем на сам регистр MOV AL,0111B ;принимаем коды 1010 или 0010 OUT DX,AL ;посылаем данные ;---поиск цвета MOV AX,0A000H ;адрес видеобуфера MOV ES,AX ; MOV BX,12 ;смещение в буфере MOV AL,ES:[BX] ;читаем позицию буфера CMP AL,0 ;установлены биты? JNZ FOUND_IT ;если да, то ищем у какой точки 4.4.5 Рисование линий на экране. Простейший способ нарисовать линию на экране состоит в том, чтобы вычислить следующую точку этой линии и изменить биты соот- ветствующего байта. Такие операции очень медленны, хотя иногда их нельзя избежать. Если это возможно, то лучше вычислить область точек экрана, которые имеют одинаковый цвет. Тогда требуемые операции над битами можно проделать только над одним байтом, а затем этот байт может быть помещен в область соответствующих позиций видеобуфера. Высокий уровень. Бейсик позволяет рисовать прямые линии с помощью оператора LINE. LINE (20,10)-(40,30) рисует линию от столбца 20 и строки 10 к столбцу 40 и строке 30. И строки и столбцы нумеруются от нуля. Вы можете опустить координаты первой точки, в этом случае линия будет начинаться с последней точки, которая была ранее выведена графическим оператором. Вторая пара координат может задаваться также относительно первой, с помощью конструкции LINE -STEP(xoff- set,yoffset). Оператор LINE может указывать также цвет и стиль линии. Код цвета следует сразу за списком координат; LINE (50,50)-(60,60),2 выводит линию цветом 2. Когда цвет не указан, то по умолчанию берется цвет 3. Возможность выбора стиля линии предполагает ука- зание чередования ее точек. Образец может даваться как в десятич- ной, так и в шестнадцатиричной форме. Например, образец 1010101010101010, который соответствует &HAAAA, дает линию, точки которой имеют по очереди данный цвет и фоновый. Стиль линии опре- деляется третьим параметром после координат. Например, LINE (30,30)-(40,40),3,,&HAAAA выводит линию с указанным стилем цветом 3. Бейсик предоставляет также процедуры для рисования прямоуголь- ников и окружностей. Прямоугольники выводятся с помощью оператора LINE. В данном случае координаты должны описывать левый верхний и правый нижний угол рамки. Надо просто указать B (box - т.е. рам- ка) в качестве второго параметра за координатами. LINE (50,50)-(100,100),1,B,&HAAAA рисует квадрат со стороной 50 точек цветом 1 палетты, используя вышеописанный стиль. Для вывода пря- моугольника, заполненного определенным цветом надо использовать параметр BF (при этом стиль линии указывать не надо). Окружности рисуются оператором CIRCLE. Их вывод основывается на формуле CIRCLE (x,y),r,цвет,нач-угол,кон-угол,аспект. Коорди- наты x,y дают адрес центра окружности на экране, а r - радиус окружности в точках; вся остальная информация необязательна. Цвет - это код цвета, который по умолчанию берется равным 3. Если необходимо вывести только дугу окружности, то можно указать нач-угол и кон-угол (когда они опущены, то выводится целая окруж- ность). Углы измеряются как положительные или отрицательные ве- личины, отсчитываемые от направления по горизонтали вправо. Они измеряются в радианах (в 360 градусах содержится 6.292 радиан, а один градус = 0.0174532 радиан). Аспект это отношение горизон- тальных и вертикальных размеров. Круглая окружность получается на дисплее, когда Вы укажете его равным 5/6 для умеренного разреше- ния и 5/12 для высокого разрешения. Меньшие значения приводят к эллипсам, вытянутым по горизонтали, а большие - по вертикали. Для примера PI=3.14159: CIRCLE(200,50),30,2,PI/2,PI,6 выводит дугу, центр которой находится в точке 50,200, с радиусом 30 точек цве- том 2, причем будет выведен только левый верхний квадрант верти- кально вытянутого эллипса. Более сложные линии могут выводиться с помощью оператора DRAW, который необычайно гибок. За оператором DRAW следует строка (зак- люченная в скобки), в которой закодирована последовательность ориентаций и длин сегментов, составляющих линию. Например, DRAW "E12F12G12H12" выводит бубну. Начальная точка устанавливается оператором PSET (обсуждаемым в [4.4.2]); в противном случае, по умолчанию берется центр экрана. Основные коды состоят из буквы, за которой следует длина сегмента в точках. Коды следующие: Ux вверх (на x точек) Dx вниз Rx вправо Lx влево Ex по диагонали вверх и вправо Fx по диагонали вниз и вправо Gx по диагонали вниз и влево Hx по диагонали вверх и влево При умеренном разрешении 100 точек по горизонтали и 100 точек по вертикали дают отрезки примерно одинаковой длины (на самом деле отношение y к x равно 5/6). При высоком разрешении горизонтальная линия будет приблизительно вдвое меньше, чем вертикальная. Из-за большего расстояния между точками диагональ прямоугольника содер- жит ровно столько же точек, сколько и максимальная сторона пря- моугольника, хотя сам отрезок длиннее. Для рисования диагоналей с углами, отличными от 45 градусов, используется кодовая буква M. Этот код рисует следующий сегмент линии в абсолютную или относительную позицию экрана. Чтобы ука- зать абсолютную позицию надо указать координаты x и y. DRAW "M50,60" проведет линию в точку, имеющую координаты столбца 50 и строки 60. Для указания относительных координат добавьте знаки + или - перед числами. Если текущее значение координаты x равно 100, то +50 продолжит линию до столбца 150, а -50 - до столбца 50. Чтобы сдвинуться из 100,100 в 120,70 напишите DRAW "M+20,-30". Линия не обязана быть непрерывной. Когда перед кодом указана буква B, то указатель перемещается как указано, но сегмент линии при этом не рисуется. Например, DRAW "L10BU5R10" рисует две пара- ллельные горизонтальные линии. Чтобы из одной точки начиналось несколько сегментов надо указать перед кодом букву N. В этом случае указатель будет возвращаться в начальную точку после выво- да сегмента. Имеется ряд специальных кодов, которые будучи помещенными внутри строки, действуют на все последующие коды (пока следующий аналогичный код не укажет другое действие). Цвет сегмента линии устанавливается буквой C, за которой следует код цвета. DRAW "C2D5" рисует линию, направленную вниз цветом 2. Установка масш- табного фактора меняет масштаб, в котором будет выводиться фигура или ее часть. Надо добавить к строке букву S, за которой следует фактор. Фактор это число, которое для получения масштаба делится на 4. Обычно фактор равен 4, что соответствует масштабу 1:1. Изменение фактора на 8 приведет к тому, что размер выводимой фигуры будет вдвое больше. Для этого напишите DRAW "S8U12D12" и т.д. Используя один их двух кодов Вы можете вращать оси координат- ной системы. Кодовая буква A вращает оси против часовой стрелки с 90-градусными инкриментами. A0 не вращет оси вообще. A1 - повора- чивает их на 90 градусов, A2 - на 180 градусов и A3 - на 270 градусов. Аналогично, код TA поворачивает оси на указанное число градусов от 0 до 360 (против часовой стрелки) и от 0 до -360 (по часовой стрелке). DRAW "A1L10" и DRAW "TA90L10" приведут к тому, что линия, которая должна была быть направленной влево будет вместо этого нарисована повернутой на 90 градусов и направлена вниз. Оператор DRAW может включать строковые переменные, которые состоят из набора допустимых кодов. Это свойство позволяет прог- рамме повторно использовать части фигур в различных рисунках. В операторе DRAW имя строки должно быть помещено за буквой X и за ним должны следовать точка с запятой. Например: 100 S$ = "U12R15U45L32" 110 DRAW "XS$;" В одном операторе DRAW может содержаться несколько строк, переме- жаемых другими кодами. Отметим, что любые числа, используемые с кодами в операторах DRAW могут сами быть переменными. Таким обра- зом с помощью одного оператора DRAW могут выводиться фигуры, отличающиеся по форме, цвету, масштабу и ориентации. Надо помес- тить знак равенства между буквенным кодом и именем переменной, а за именем поместить точку с запятой. Например, чтобы установить код цвета, определяемый переменной, напишите DRAW "C=PCOLOR;". Компилятор Бейсика требует, чтобы ссылка на эти переменные осу- ществлялась с помощью функции VARPTR$. В этом случае такой опера- тор будет иметь вид DRAW "X" + VARPTR$(S$) или DRAW "C=" + VARPTR$(PCOLOR). Сложные рисунки могут быть сохранены в массиве и затем возвращены на экран в любой момент. Обсуждение этого вопро- са см. в [4.4.6]. Низкий уровень. Нижеприведенная процедура использует алгоритм Брезенхэма для вывода прямой линии, соединяющей любые две точки. Она использует функцию BIOS установки точек и ее можно убыстрить если заменить эту функцию на встроенную процедуру, использующую прямое отобра- жение в память. Как и все быстрые алгоритмы данная процедура избегает операций умножения и деления. Линия рассматривается как набор сегментов двух типов: тех которые расположены диагонально и тех, которые расположены горизонтально или вертикально. Для линий с наклоном больше 1 прямые сегменты вертикальны, в противном случае они горизонтальны; первая задача алгоритма состоит в вы- числении наклона. Затем вычисляется выравнивающий фактор, который следит чтобы некоторое число прямых сегментов имело большую дли- ну, чем остальные. И, наконец, сложный цикл поочередно выводит диагональные и прямые сегменты. BX поочередно принимает то поло- жительные, то отрицательные значения, отмечая какой тип сегмента выводится. Ниже готовятся данные для вывода диагонали из одного угла экрана в противоположный: ;---в сегменте данных START_X DW 0 END_X DW 319 START_Y DW 0 END_Y DW 199 COLOR DB 2 DIAGONAL_Y_INCREMENT DW ? DIAGONAL_X_INCREMENT DW ? SHORT_DISTANCE DW ? STRAIGHT_X_INCREMENT DW ? STRAIGHT_Y_INCREMENT DW ? STRAIGHT_COUNT DW ? DIAGONAL_COUNT DW ? ;---установка режима дисплея MOV AH,0 ;функция установки режима MOV AL,4 ;цветной 320*200 INT 10H ;установка режима ;---установка начальных инкрементов для каждой позиции точки MOV CX,1 ;инкремент для оси x MOV DX,1 ;инкремент для оси y ;---вычисление вертикальной дистанции MOV DI,END_Y ;вычитаем координату начальной SUB DI,START_Y ;точки из координаты конечной JGE KEEP_Y ;вперед если наклон < 0 NEG DX ;иначе инкремент равен -1 NEG DI ;а дистанция должна быть > 0 KEEP_Y: MOV DIAGONAL_Y_INCREMENT,DX ;---вычисление горизонтальной дистанции MOV SI,END_X ;вычитаем координату начальной SUB SI,START_X ;точки из координаты конечной JGE KEEP_X ;вперед если наклон < 0 NEG CX ;иначе инкремент равен -1 NEG SI ;а дистанция должна быть > 0 KEEP_X: MOV DIAGONAL_Y_INCREMENT,CX ;---определяем горизонтальны или вертикальны прямые сегменты CMP SI,DI ;горизонтальные длиннее? JGE HORZ_SEG ;если да, то вперед MOV CX,0 ;иначе для прямых x не меняется XCHG SI,DI ;помещаем большее в CX JMP SAVE_VALUES;сохраняем значения HORZ_SEG: MOV DX,0 ;теперь для прямых не меняется y SAVE_VALUES: MOV SHORT_DISTANCE,DI ;меньшее расстояние MOV STRAIGHT_X_INCREMENT,CX ;один из них 0, MOV STRAIGHT_Y_INCREMENT,DX ;а другой - 1. ;---вычисляем выравнивающий фактор MOV AX,SHORT_DISTANCE ;меньшее расстояние в AX SHL AX,1 ;удваиваем его MOV STRAIGHT_COUNT,AX ;запоминаем его SUB AX,SI ;2*меньшее - большее MOV BX,AX ;запоминаем как счетчик цикла SUB AX,SI ;2*меньшее - 2*большее MOV DIAGONAL_COUNT,AX ;запоминаем ;---подготовка к выводу линии MOV CX,START_X ;начальная координата x MOV CX,START_Y ;начальная координата y INC SI ;прибавляем 1 для конца MOV AL,COLOR ;берем код цвета ;---теперь выводим линию MAINLOOP: DEC SI ;счетчик для большего расстояния JZ LINE_FINISHED ;выход после последней точки MOV AH,12 ;функция вывода точки INT 10H ;выводим точку CMP BX,0 ;если BX < 0, то прямой сегмент JGE DIAGONAL_LINE ;иначе диагональный сегмент ;---выводим прямые сегменты ADD CX,STRAIGHT_X_INCREMENT ;определяем инкре- ADD DX,STRAIGHT_Y_INCREMENT ;менты по осям ADD BX,STRAIGHT_COUNT ;фактор выравнивания JMP SHORT MAINLOOP ;на следующую точку ;---выводим диагональные сегменты DIAGONAL_LINE: ADD CX,DIAGONAL_X_INCREMENT ;определяем инкре- ADD DX,DIAGONAL_Y_INCREMENT ;менты по осям ADD BX,DIAGONAL_COUNT ;фактор выравнивания JMP SHORT MAINLOOP ;на следующую точку LINE_FINISHED: 4.4.6 Заполнение областей экрана. Тщательное обдумывание позволяет исключить много излишней медлительности, которая свойственна многим программам заполнения областей для графического экрана. Когда заполнение основано на простых вычислениях, которые действуют по очереди для каждой точки, то требуются расходующие много времени битовые операции. Более экономный код может определять все ли битовые позиции опре- деленного байта видеобуфера должны иметь один и тот же цвет и когда это условие выполняется, то этому байту присваивается зара- нее заготовленное значение, которое устанавливает все точки в правильный цвет. При этом нет необходимости повторять операции над одним и тем же байтом, каждый раз устанавливая биты только для одной из точек, информацию о которой содержит данный байт. В [4.3.4] объяснено как создать описание символа в виде матри- цы 8*8 точек, имеющего требуемый Вам вид. Хотя такие символы могут выводиться только в стандартные символьные позиции, но их использование может существенно облегчить заполнение графиков. Образец высвечивающий все 8*8 точек может быть выведен в интерва- ле нескольких строк и столбцов, заполняя область намного быстрее, чем это достигается при поточечной зарисовке. Этот тип графичес- ких символов может использоваться совместно с точечной графикой. Псевдографические символы могут использоваться также для вывода вращающихся или колеблющихся объектов. Высокий уровень. Бейсик предоставляет оператор PAINT для заполнения замкнутой фигуры произвольной формы. Вам необходимо указать только точку внутри области, а об остальном позаботится процедура. Может быть указан цвет палетты, которым надо заполнить область, например, PAINT (100,110),2 заполняет область цветом 2 палетты. Закраска ведется начиная от указанной точки до тех пор, пока не встретятся точки с цветом, отличающимся от фонового. Вы можете, наоборот, указать цвет границы и закраска будет продолжаться во всех нап- равлениях, пока не будут встречены точки указанного цвета. При такой закраске линии других цветов, находящиеся внутри границы, могут быть также закрашены. Код цвета границы следует за кодом цвета заполнения, таким образом PAINT (100,180),2,3 закрашивает область цветом 2 до линий цвета 3. Отметим, однако, что эта про- цедура не заполняет области, находящиеся "за углом", т.е. если вдоль какой-либо горизонтальной или вертикальной траектории встретилась точка, имеющая цвет границы, то все последующие точки вдоль этой траектории не заполняются, даже если фигура имеет причудливую форму и эти точки принадлежат внутренней части фигу- ры. В следующем примере выводятся две перекрывающихся рамки цве- тами циан и магента, а затем последняя рамка заполняется белым цветом. Сегменты первой рамки, которые попадают в закрашенную область также заполняются белым. 100 LINE (50,70)-(270,130),1,B 'рисуем рамку цветом циан 110 LINE (100,30)-(220,170),2,B 'рисуем рамку цветом магента 120 PAINT (101,31),3,2 'заполняем вторую рамку белым Помните, что команда LINE может сама заполнить рамку, если Вы укажете в качестве параметра 'BF', а не 'B'. Смотрите [4.4.5]. Оператор PAINT имеет "орнаментальные" возможности, которые позволяют Вам заполнять области указанной картинкой. Элементы орнамента, которые в режиме умеренного разрешения имеют размер 4 точки в ширину и 8 в высоту (8*8 для высокого разрешения) повто- ряются по всей указанной области. Рисунок описывается набором байтов, содержащих цепочку битов для последовательных рядов эле- мента орнамента. В режиме умеренного разрешения цепочка битов 10000011 описывает 4 точки, первая из которых имеет цвет 2, сле- дующие 2 - фоновый цвет, а последняя - цвет 3. Эта цепочка соот- ветствует числу 131 или &H83 (см. приложение Б, в котором обсуж- даются битовые операции в Бейсике). Обращение этой цепочки в 11000010 даст 193 (&HC1). Они могут быть объединены в элемент орнамента шириной в 4 точки и высотой в 2 строкой CHR$(&H83) + CHR$(&HC1). В такую строку могут включаться до 8 байтов, доводя высоту до 8 точек. Такая строка используется в операторе PAINT вместо цвета. Вот вывод квадрата, заполненного описанным орнамен- том: 100 LINE (100,110)-(150,150),1,B 'рисуем рамку 110 PAINT (125,125),CHR$(&H83)+CHR$(&HC1),1 'заполняем ее Отметим, что нерегулярности элемента орнамента могут приводить к тому, что процедура PAINT завершается, не закончив заполнения области. Бейсик решает эту проблему указанием параметра фона для оператора PAINT. Если у Вас возникнут проблемы, обращайтесь к руководству по Бейсику за деталями. Оператор DRAW, позволяющий рисовать сложные линии, также может заполнять области. Он обсуждается в [4.4.5]. "Текущая точка" (из которой будет рисоваться следующий сегмент линии) должна быть помещена внутрь области, ограниченной границей указанного цвета. В строку оператора DRAW надо поместить кодовую букву P, за кото- рой должен следовать код цвета закраски и код цвета границы. Для вывода рамки цветом 1 палетты, а затем ее заполнения цветом 3 напишите DRAW "U10R10D10L10BH1P3,1". Здесь первые четыре кода рисуют границы рамки, затем код 'BH' перемещает текущую точку внутрь рамки, не рисуя линии, а затем код 'P' приводит к заполне- нию рамки. Таким образом могут быть заполнены и более сложные формы. Отметим, что необязательно при перемещении точки внутрь области отменять рисование линии вдоль этого пути. Однако, в этом случае надо использовать для этого сегмента код цвета, отличный от цвета заполняемой границы. Бейсик имеет также возможность заполнения областей экрана заранее подготовленным изображением. Изображение может быть любо- го размера, может быть выведено в любой позиции экрана и хранится в массиве. Обычно, изображение создается с помощью всех доступных средств, а затем запоминается в массиве оператором GET. Массив может быть помещен в последовательный файл [5.4.3], из которого программа может загрузить его и вывести изображение. Оператор GET перечисляет координаты левого верхнего и правого нижнего угла рамки, содержащей изображение, причем сначала идет номер столбца, а затем номер строки для каждой пары координат. Затем должно следовать имя массива, которое не заключается в кавычки. Напри- мер, GET (80,40)-(120,60),ARRAY3 помещает все точки, находящиеся внутри указанной области в массив с именем ARRAY3. Одномерные массивы, как и все остальные, должны быть предвари- тельно описаны оператором DIM. Массив может содержать элементы любой точности. Для вычисления требуемых размеров массива надо сначала определить сколько байтов потребуется для хранения изоб- ражения. Это можно вычислить по формуле 4 + INT ((x*битовнаточку + 7)/8)* y. Здесь "битовнаточку" равно 1 для высокого разрешения и 2 - для умеренного разрешения. Буквы x и y относятся к числу точек вдоль горизонтальной и вертикальной сторон блока изображе- ния. INT обозначает целую часть числа. Наконец, надо определить сколько элементов массива требуется для хранения данного числа байтов. Каждый элемент занимает 2 байта в целом массиве, но 4 - для чисел с обычной точностью и 8 - для чисел с двойной точно- стью. Для получения изображения из массива и вывода его на экран используйте оператор PUT. Этот оператор требует только координаты левого верхнего угла области экрана, в которую будет выводиться изображение. За координатами должно быть указано имя массива. Например, PUT (40,30),ARRAY1 помещает изображение, левый верхний угол которого будет находиться в столбце 40 и строке 30. Оператор PUT может иметь еще и необязательный параметр, определяющий цвет, которым будет выводиться изображение. Если этот параметр опущен, то изображение будет выводиться точно в том виде, в котором оно было записано оператором GET. Это эквивалентно записи PUT (40,30),ARRAY1,PSET. В противном случае имеются некоторые другие возможности. Если Вы вместо PSET укажете PRESET, то цвет 0 палет- ты будет заменен на цвет 3 и наоборот, а цвет 1 палетты - на цвет 2 и наоборот. Имеются еще три случая, использующие логические операции AND, OR или XOR. Как и PRESET эти слова могут заменять PSET в приве- денном примере. Обсуждение этих трех операций смотрите в приложе- нии Б. Каждая операция включает сравнение битов существующей точки на экране с битами точки накладываемого изображения. В режиме высокого разрешения, когда на точку отводится только 1 бит операция простая. Но в режиме умеренного разрешения, в котором на каждую точку отводится 2 бита, могут происходить различные транс- формации цветов. AND устанавливает бит только если он был установлен и у точки экрана и у точки изображения (взятой из массива). В режиме высо- кого разрешения это означает, что точка изображения появится на экране только если соответствующая точка экрана уже "включена". Все остальные точки области будут выключены. В режиме умеренного разрешения операция производится над обоими битами. Если для точки экрана установка битов 01, а для соответствующей точки изображения - 10, то оба бита будут сброшены и точка экрана полу- чит код 00, что соответствует фоновому цвету. OR устанавливает бит, если он был установлен либо для точки экрана, либо для точки изображения. В черно-белом режиме OR нак- ладывает изображение на существующее изображение на экране. В цветном режиме для определения эффекта Вы опять должны прибегнуть к вычислениям. Комбинация кодов палетты 1(01) и 2(10) дает 3(11), также как и комбинация 0(00) и 3(11). И, наконец, XOR устанавливает бит, если из двух сравниваемых только один был установлен. Применение этой операции для чер- но-белого экрана с массивом единиц дает негативное изображение (1 и 1 дает 0, а 1 и 0 - дает 1). В режиме умеренного разрешения эта операция меняет все цвета. В результате получаем наложение двух изображений. Но более важно, что при повторении этой операции экран принимает в точности такой же вид, который он имел первона- чально. При этом изображение стирается. Эта техника полезна для мультипликации, когда над изображением дважды производится опера- ция XOR в одной позиции, затем в соседней и т.д. Низкий уровень. Имеется много подходов к написанию процедур заполнения графи- ческих объектов. Ни один из них не является идеальным, поскольку всегда имеется конфликт между скоростью работы процедуры и слож- ностью фигур, которые она может обрабатывать. Любая процедура, которая заполняет область точку за точкой будет медленной, неза- висимо от того, насколько элегантно она реализована. Имейте вви- ду, что почти каждая модифицируемая точка расположена в байте, все точки которого будут изменяться в тот же самый цвет. Получе- ние доступа к одному и тому же байту с использованием сложных процедур требует существенно больше времени, чем установка целого байта за один доступ к ячейке видеобуфера. Например, поточечная очистка экрана требует на IBM PC нескольких секунд при использо- вании функции BIOS, в то время как прямой доступ в память произ- водит эту операцию мгновенно: MOV AX,0B800H ;ES указывает на буфер экрана MOV ES,AX ; MOV CX,8192 ;заполняем все байты MOV AX,0 ;в каждый байт пишем 0 MOV DI,0 ;DI поочередно указывает на все байты REP STOSW ;повторяем запись 8192 раза Многие процедуры заполняют по одной горизонтальной строке, проверяя на цвет границы справа и слева. Поскольку строки состоят из смежных байтов данных, то надо поочередно брать байты из ви- деобуфера и проверять присутствует ли в них цвет границы. Если цвет границы отсутствует, то можно заменить сразу весь байт на цвет заполнения. В противном случае к данному байту применяется поточечный подход. Имеется очень быстрый способ определения присутствует ли гра- ничный цвет в данном байте видеобуфера. Предположим, что процеду- ра ищет цвет 1 палетты в режиме умеренного разрешения с четырьмя цветами. Этому цвету соответствует код 01, поэтому сначала запол- ним весь байт этим кодом: 01010101. Затем используем операцию NOT для обращения каждого бита, после чего байт примет вид 10101010. Проделаем операцию XOR со значением взятым из видеобуфера; в результате получим байт, у которого оба бита, относящиеся к одной точке равны 1 только для точек, имеющих граничный цвет. Затем снова используем операцию NOT с тем, чтобы пара битов, относящих- ся к точке граничного цвета имела код 00. После этого используем операцию TEST для нахождения полей со значением 00. Если такое поле найдено, то граничный цвет обнаружен и процедура переходит к обычному поточечному анализу данного байта. Эту процедуру можно еще убыстрить, если использовать словные данные. MOV AL,ES:[BX] ;берем байт из видеобуфера XOR AL,10101010B ;устанавливаем биты для цвета границы NOT AL ;обращаем биты TEST AL,11000000B ;проверяем биты 7-6 JZ FOUND_BOUND ;переход если граничный цвет TEST AL,00110000B ;проверяем биты 5-4 JZ FOUND_BOUND ;переход если граничный цвет TEST AL,00001100B ;проверяем биты 3-2 JZ FOUND_BOUND ;переход если граничный цвет TEST AL,00000011B ;проверяем биты 1-0 JZ FOUND_BOUND ;переход если граничный цвет MOV AL,FILL_COLOR ;граничного цвета нет, заполняем байт MOV ES:[BX],AL ;возвращаем байт в видеобуфер . . FOUND_BOUND: Когда это возможно, постарайтесь, чтобы границы прямоугольных областей Ваших картинок были выравнены на границу двух, четырех или восьми точек, с тем чтобы прямое отображение в память имело дело с целыми байтами. Другая возможность, хотя и не столь быст- рая, состоит в создании определяемых пользователем псевдографи- ческих символов [4.3.4] и выводе их на границе области заполне- ния. Короче, в данной области Вы имеете все возможности проявить сообразительность, а зачастую стоит подумать, а нужна ли Вам столь сложная графика в данной задаче. 4.4.7 Графический вывод с использованием символов псевдографики. Когда Вы выводите изображение точка за точкой, то это отнимает очень много времени, особенно когда создаются эффекты мультипли- кации. Один из способов экономии времени состоит в сведении всех или части выводимых форм к фигурам, которые могут быть построены на матрице точек 8*8. Такие фигуры могут быть созданы, как опре- деляемые пользователем символы, как показано в [4.3.4]. После того, как эти символы определены они выводятся на экран очень быстро и просто. Эти символы могут выводиться вперемешку с пото- чечными графиками, как обычные буквы. Один из способов быстрого заполнения фигуры состоит в последовательном выводе внутри фигуры полностью закрашенного блока. Отметим, что эти символы всегда располагаются в стандартных позициях курсора. Средний уровень. В этом примере рисуется фигура человека, занимающая 2 символа в высоту и 2 символа в ширину. Как объяснено в [4.3.4] вектор прерывания 1FH указывает на начало области данных, определяющих символы. Четыре символа могут быть выведены обычными процедурами DOS или BIOS. Легко создать другой набор символов, для вывода фигуры с руками и ногами в другом месте экрана. Два набора симво- лов могут поочередно меняться в соседних позициях курсора, созда- вая иллюзию человека, идущего по экрану. ;---в сегменте данных CHARACTER_DATA DB 00110000B ;левый верхний квадрант DB 01100111B DB 01100111B DB 00110011B DB 00011111B DB 00001111B DB 00001111B DB 00000111B DB 00000011B ;правый верхний квадрант DB 10001100B DB 10011000B DB 00110000B DB 11100000B DB 11000000B DB 11000000B DB 10000000B DB 00001111B ;левый нижний квадрант DB 00011111B DB 00011100B DB 00011000B DB 00011000B DB 00110000B DB 01100000B DB 00010000B DB 11000000B ;правый нижний квадрант DB 11000000B DB 11000000B DB 11000000B DB 01100000B DB 01100000B DB 00010000B DB 00011110B DB 00000000B ;---установка вектора прерывания PUSH DS ;сохраняем DS MOV DX,OFFSET CHAR_DATA ;смещение для данных в DX MOV AX,SEG CHAR_DATA ;сегмент для данных в DS MOV DS,AX ; MOV AH,25H ;функция установки вектора MOV AL,1FH ;номер вектора INT 21H ;устанавливаем вектор POP DS ;восстанавливаем DS ;---рисуем фигуру ;---позиционируем курсор на верхний ряд MOV AH,2 ;функция установки курсора MOV DH,13 ;строка 13 MOV DL,20 ;столбец 20 MOV BH,0 ;страница 0 INT 10H ;установка курсора ;---рисуем верхние два символа MOV DL,128 ;берем символ 128 MOV AH,2 ;функция вывода/курсор вперед INT 21H ;вывод символа MOV DL,129 ;берем символ 129 INT 21H ;выводим его ;---позиционируем курсор на нижнюю строку MOV DH,14 ;строка 14 MOV DL,20 ;столбец 20 MOV AH,2 ;функция установки курсора INT 10H ;устанавливаем курсор ;---рисуем нижние два символа MOV DL,130 ;берем символ 130 MOV AH,2 ;функция вывода/курсор вперед INT 21H ;вывод символа MOV DL,131 ;берем символ 131 INT 21H ;выводим его Раздел 5. Сдвиг экрана и страницы. Сдвиг экрана и разбиение на страницы - это два способа перено- са блока информации из памяти на экран. При сдвиге одна из границ экрана сдвигается внутрь, стирая информацию на противоположной стороне. Затем освободившаяся область заполняется из памяти. Повторение этого действия строка за строкой создает иллюзию сдви- га экрана. С другой стороны, разбиение на страницы основано на одновре- менном хранении нескольких экранов информации в видеобуфере и переключении вывода с одной страницы на другую. Использование дисплейных страниц невозможно на монохромном адапторе, поскольку его памяти хватает только для одного символьного экрана. Другие видеосистемы в большинстве экранных режимов могут работать с несколькими страницами. Использование страниц дисплея особенно полезно при построении сложных картин "за кулисами"; после того как эта работа завершена, новый экран выводится моментально. Процедура, имитирующая работу со страницами для монохромного адаптора приведена в [4.5.3]. Она особенно полезна, когда Вы имеете дело с медленным выводом на экран в Бейсике. 4.5.1 Вертикальный сдвиг текстового экрана. Когда текстовый экран сдвигается вверх, то строки со 2-й по 25-ю переписываются на строки с 1-й по 24-ю, а следующая строка данных выводится в 25-й строке. При этом верхняя строка, поверх которой осуществлется вывод теряется, хотя она продолжает су- ществовать в памяти. Сдвиг вниз устроен аналогично. Высокий уровень. Бейсик утомительно медлителен при своих манипуляциях с экра- ном. Для быстрого сдвига Вы можете пожелать использовать процеду- ру на машинном языке, которая не делает ничего другого, кроме как использует прерывание 10H, как описано ниже в пункте средний уровень. Процедура позволяет сдвигать весь экран или любое окно в нем. Приложение Г показывает как включать подпрограммы на машин- ном языке в Ваши программы. Ваша программа на Бейсике должна указывать координаты верхнего левого и нижнего правого углов окна, которые могут лежать в диапазоне от 0 до 24 и от 0 до 79. Требуется также параметр, указывающий направление сдвига: вверх или вниз (6 и 7, соответственно), число строк на которое нужно сдвинуть (если 0, то окно очищается) и значение байта атрибутов для очищаемых строк (для "нормальных" - 7). Используйте для них целые переменные. В нижеприведенно примере экран сдвигается вниз на одну строку, а затем освободившаяся строка освобождается. 100 '''данные для подпрограммы 110 DATA &H55, &H8B, &HEC, &H8B, &H76, &H12, &H8A 120 DATA &H24, &H8B, &H76, &H10, &H8A, &H04, &H8B 130 DATA &H76, &H0E, &H8A, &H2C, &H8B, &H76, &H0C 140 DATA &H8A, &H0C, &H8B, &H76, &H0A, &H8A, &H34 150 DATA &H8B, &H76, &H08, &H8A, &H14, &H8B, &H76 160 DATA &H06, &H8A, &H3C, &HCD, &H10, &H5D, &HCA 170 DATA &H0E, &H00 180 '''помещаем данные в сегмент &H2000 190 DEF SEG = &H2000 'помещаем данные начиная с &H2000 200 FOR N = 0 TO 43 '44 байта 210 READ Q 'читаем один байт 220 POKE N,Q 'помещаем его в память 230 NEXT 'следующий 300 '''в программе 310 GOSUB 500 'сдвигаем на строку 320 LOCATE 1,1: PRINT TEXT$(LINEPTR); 'выводим строку текста 500 '''подпрограмма сдвига 510 DEFINT A-Z 'используем целые переменные 520 TLR = 0 'левая верхняя строка 530 TLC = 0 'левый верхний столбец 540 BRR = 24 'нижняя правая строка 550 BRC = 79 'нижний правый столбец 560 NUMROWS = 1 'число строк сдвига 570 DIR = 7 'направление сдвига вниз 580 FILL = 7 'заполнение обычным атрибутом 590 DEF SEG = &H2000 'указываем на подпрограмму 600 SCROLL = 0 'начинаем с 1-го байта 610 CALL SCROLL(DIR,NUMROWS,TLR,TLC,BRR,BRC,FILL) 620 RETURN 'все сделано Средний уровень. Функция 6 прерывания 10H сдвигает любую часть экрана вверх, а функция 7 - вниз. В обоих случаях AL содержит число строк сдвига, а когда AL = 0, то весь экран чистится, а не сдвигается. CH:CL содержат строку и столбец левого верхнего угла, а DH:DL - содер- жат координаты правого нижнего угла. Появлящиеся из-за сдвига строки чистые и они выводятся с кодом атрибутов из BH. ;---сдвиг вверх на одну строку MOV AH,6 ;номер функции сдвига вверх MOV AL,1 ;число строк сдвига MOV CH,0 ;строка левого верхнего угла MOV CL,0 ;столбец левого верхнего угла MOV DH,24 ;строка правого нижнего угла MOV DL,79 ;столбец правого нижнего угла MOV BH,7 ;атрибуты очищаемой строки INT 10H ;делаем сдвиг Низкий уровень. Вертикальный сдвиг всего экрана это тривиальная задача, пос- кольку правая граница одной строки в памяти продолжается левой границей следующей строки. Сдвиг всего содержимого видеобуфера на 160 байт вверх по памяти (80 символов в строке * 2 байта на сим- вол) приводит к сдвигу экрана вниз на одну строку. Если Вы пишете свою собственную процедуру сдвига экрана, использующую прямое отображение в память, то не забывайте об интерференции, которая возникает на цветном дисплее и PCjr. Эта проблема обсуждается в [4.3.1]. Обычное решение этой проблемы состоит в проверке статус- ного байта, ожидая пока он разрешит запись в видеобуфер. Вам придется поэкспериментировать, чтобы определить сколько данных Вы можете записать за один цикл. Другое решение этой проблемы состоит в выключении экрана на время операции сдвига, а затем в его восстановлении. "Выключение экрана" подразумевает, что вывод содержащихся в видеобуфере дан- ных запрещен, но сам буфер при этом не изменяется. Этот процесс используется функцией сдвига BIOS, использованной выше. Хотя это не очень приятно для глаз, но все-таки не так плохо, как уже упоминавшаяся интерференция. Для выключения экрана у цветного графического дисплея надо сбросить бит 3 порта с адресом 3D8H. Изменение бита назад на 1 моментально включает экран обратно. Этот адрес порта соответст- вует регистру выбора режима цветного графического адаптора. Этот одноба