го 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 для высокого разрешения) повто- ряются по всей указанной области. Рисунок описывается набором байтов, содержащих цепочку битов для последовательных рядов эле- мента орнамента. В р