





                        Глава 9. ПРОГРАММИРОВАНИЕ EGA И VGA



                        Мониторы и возможности EGA
                        Прямая запись на экран
                        Много точек
                        Чтение битовых матриц
                        Цветовые палитры EGA
                        Регистр циклического сдвига данных
                        Режим отображения 256 цветов VGA
                        Заключение





             Усовершенствованный графический адаптер (EGA) и  более  новая
         видеографическая матрица (VGA) предлагают разработчику единствен-
         ные в своем роде задачи.  EGA становится традиционной графической
         картой в мире MS-DOS.  Тем не менее, существует четыре совершенно
         различных графических стандарта поддержки EGA:

             1. Графические режимы, совместимые с CGA.
             2. Два  новых графических режима EGA для 200-строчных цветных
                мониторов.
             3. Новый графический режим EGA для 350-строчных цветных мони-
                торов.
             4. Новый  графический режим EGA для использования с монохром-
                ными (текстовыми) мониторами.

             Помимо всех указанных режимов, VGA поддерживает еще несколько
         новых.  В  этой  главе рассматриваются концепции программирования
         каждого нового графического режима EGA, а также новые режимы VGA.
         Не охватываются совместимые с CGA текстовый и графический режимы,
         так как они более приемлемы для карты CGA.
             Оригинальная плата  EGA фирмы IBM поступает с 64К графической
         памяти.  Она может быть расширена до 256К. Чем больше память EGA,
         тем шире графические возможности адаптера.  EGA-совместимые карты
         других производителей обычно поступают с уже  установленными 256К
         памяти.  Карты  VGA  в большинстве новых персональных компьютерах
         IBM System 2 включены в объединительную плату;  для других ПК VGA
         доступна в качестве платы расширения.  В каждом случае VGA всегда
         будет иметь установленными 256К памяти.
             Видеофункции  компьютера  IBM  PC вызываются прерыванием BIOS
         10h. Эти видеофункции позволяют программе устанавливают текстовый
         или  графический  режимы,  считывать  или  писать одиночные точки
         растра и помещать символы на экран. Адаптер EGA имеет новую BIOS,
         которая заменяет все оригинальные функции персонального компьюте-
         ра и добавляет несколько новых. Эти функции EGA позволяют опреде-
         лять новые символы,  лучше управлять палитрой и выводом на печать
         текстовых строк.


                                      - 9-2 -

                            Мониторы и возможности EGA

             Адаптер EGA создан для работы с тремя различными типами мони-
         торов: цветным дисплеем IBM, усовершенствованным цветным дисплеем
         IBM или монохромным дисплеем IBM,  а также с эквивалентными дисп-
         леями других производителей.  Обычно,  тип используемого монитора
         определяет  графическое разрешение,  максимальное количество цве-
         тов, цветовую палитру и число элементов растра, составляющее каж-
         дый символ.  Карта VGA должна использоваться с цветным или монох-
         ромным аналоговым монитором.   Несмотря  на  то,  что  аналоговый
         монитор функционально отличается от цифрового (или ТТЛ) монитора,
         программист должен рассматривать его как цифровой монитор с высо-
         кой разрешающей способность.  Следует только обратить внимание на
         то, цветной он или монохромный.
             Цветной монитор  IBM  имеет  максимальную разрешающую способ-
         ность 640 х 200 элементов изображения.  Цветной монитор ограничен
         200  вертикальными  строками  развертки ввиду того,  что он может
         применять только одну вертикальную частоту сканирования.  При ис-
         пользовании  с  цветным  монитором адаптер EGA совместим со всеми
         текстовымы и графическими режимами цветного графического  адапте-
         ра.  Два новых графических режима,  режимы 13 и 14, используют до
         16 цветов с разрешением 320 х 200 и 640  х  200.  Тем  не  менее,
         цветной  монитор ограничивается 16-цветной фиксированной палитрой
         и 200-ми вертикальными линиями развертки.  Фиксированная  палитра
         использует те же 16 цветов, что и CGA в текстовом режиме. Исполь-
         зуемый по умолчанию прямоугольник  для  генерации  символа  имеет
         размер 8 х 8 элементов изображения. Эти режимы перечислены в таб-
         лице 9-1.
                                                         Таблица 9-1
                     Использование EGA c цветным монитором IBM
         ────┬─────────┬───────┬────────┬───────┬────────┬────┬────────
         Но- │ Тип     │Макси- │ Размер │ Размер│ Макси- │Сег-│ Разре-
         мер │         │мальное│(столбцы│ прямо-│ мальное│мент│ шение
         ре- │         │число  │ х      │ уголь-│ число  │бу- │
         жима│         │цветов │ строки)│ ника  │ страниц│фера│
         ────┼─────────┼───────┼────────┼───────┼────────┼────┼────────
          0  │ Текст   │  16   │ 40х25  │  8х8  │ 8      │В800│ 320х200
          1  │ Текст   │  16   │ 40х25  │  8х8  │ 8      │В800│ 320х200
          2  │ Текст   │  16   │ 80х25  │  8х8  │ 4/8/8* │В800│ 640х200
          3  │ Текст   │  16   │ 80х25  │  8х8  │ 4/8/8* │В800│ 640х200
          4  │ Графика │   4   │ 40х25  │  8х8  │ 1      │В800│ 320х200
          5  │ Графика │   4   │ 40х25  │  8х8  │ 1      │В800│ 320х200
          6  │ Графика │   2   │ 80х25  │  8х8  │ 1      │В800│ 640х200
         13  │ Графика │  16   │ 40х25  │  8х8  │ 2/4/8* │А000│ 320х200
         14  │ Графика │  16   │ 80х25  │  8х8  │ 1/2/4* │А000│ 640х200
         ────┴─────────┴───────┴────────┴───────┴────────┴────┴────────
         (*) - Зависит от объема установленной памяти EGA


                      Усовершенствованный графический дисплей

             Усовершенствованный графический дисплей фирмы  IBM  совместим
         со  всеми режимами цветного дисплея и использует еще один режим с
         высокой  разрешающей  способностью.  Усовершенствованный  цветной
         дисплей способен применять две вертикальные частоты сканирования,
         одну для 200-строчных режимов и одну  для  350-строчных  режимов.

                                      - 9-3 -
         Кроме двух стандартных вертикальных частот сканирования,  генери-
         руемых EGA,  мониторы с мультисинхронизацией могут использовать и
         более  высокие  частоты  для  получения более высокой разрешающей
         способности.  Режим высокого разрешения - режим 16,  может приме-
         няться только с усовершенствованным цветным дисплеем IBM, эквива-
         лентным монитором или монитором с мультисинхронизацией,  так  как
         вертикальное разрешение имеет значение 350 строк, а цветной дисп-
         лей может отображать только 200 строк.
             При использовании  с  усовершенствованным цветным монитором в
         большинстве режимов EGA может отображать 16 цветов  из 64-цветной
         палитры. 16 цветов доступны только в режиме 16 в том случае, если
         карта EGA имеет более 64К памяти.  Режимы с 4 по  6,  графические
         режимы,  совместимые с CGA, ограничены той же 16-цветной фиксиро-
         ванной палитрой, как и CGA. Текстовые режимы усовершенствованного
         цветного дисплея используют 8х14 элементов изображения для каждого
         символа, что дает символ с более высокой разрешающей способностью,
         чем символ, генерируемый в режиме CGA. Режимы усовершенствованного
         цветного  дисплея  (и  мультисинхронизационных эквивалентов) пере-
         числены в таблице 9-2.

                                                         Таблица 9-2
                      Использование EGA c усовершенствованным
               монитором IBM (или монитором с мультисинхронизацией)
         ────┬────────┬────────┬────────┬───────┬────────┬─────┬───────
         Но- │ Тип    │ Макси- │ Размер │ Размер│ Макси- │Сег- │Разре-
         мер │        │ мальное│(столбцы│ прямо-│ мальное│мент │шение
         ре- │        │ число  │ х      │ уголь-│ число  │бу-  │
         жима│        │ цветов │ строки)│ ника  │ страниц│фера │
         ────┼────────┼────────┼────────┼───────┼────────┼─────┼───────
          0  │ Текст  │   16   │ 40х25  │ 8х14  │ 8      │В800 │320х350
             │        │ из 64  │        │       │        │     │
          1  │ Текст  │   16   │ 40х25  │ 8х14  │ 8      │В800 │320х350
             │        │ из 64  │        │       │        │     │
          2  │ Текст  │   16   │ 80х25  │ 8х14  │ 4/8/8* │В800 │640х350
             │        │ из 64  │        │       │        │     │
          3  │ Текст  │   16   │ 80х25  │ 8х14  │ 4/8/8* │В800 │640х350
             │        │ из 64  │        │       │        │     │
          4  │ Графика│    4   │ 40х25  │ 8х8   │ 1      │В800 │320х200
          5  │ Графика│    4   │ 40х25  │ 8х8   │ 1      │В800 │320х200
          6  │ Графика│    2   │ 80х25  │ 8х8   │ 1      │В800 │640х200
         13  │ Графика│   16   │ 40х25  │ 8х8   │ 2/4/8* │А000 │320х200
             │        │ из 64  │        │       │        │     │
         14  │ Графика│   16   │ 80х25  │ 8х8   │ 1/2/4* │А000 │640х200
             │        │ из 64  │        │       │        │     │
         16  │ Графика│  4/16  │ 80х25  │ 8х14  │ 1/2*   │А000 │640х350
             │        │ из 64* │        │       │        │     │
         ────┴────────┴────────┴────────┴───────┴────────┴─────┴───────
         (*) - Зависит от объема установленной памяти EGA.

                          Монохромные графические режимы

             Монохромный дисплей  IBM используется в основном только в ка-
         честве текстового дисплея.  Текстовый режим совместим с монохром-
         ным адаптером IBM. Тем не менее, имеется новый режим, который до-
         бавляет графику с разрешающей  способностью  640х350  и  четырьмя
         "цветами": черным, видимым, мерцающим видимым и интенсивным види-
         мым.  Если монохромный монитор подключен к EGA,  то EGA не  может

                                      - 9-4 -
         использовать  ни  один  из своих цветных графических режимов,  но
         способна применять новый монохромный графический режим.
             EGA преобразует шрифт 8х14,  используемый с расширенным цвет-
         ным монитором в MDA-совместимый шрифт 9х14.  Это достигается рас-
         ширением любых символов,  формирующих строки,  в позицию девятого
         элемента изображения.  Не путайте подключение EGA к  монохромному
         монитору  с подключением VGA к аналоговому монохромному монитору.
         VGA в этом случае трактуется как подключенная к цветному монитору
         с высоким разрешением или к цифровому монохромному монитору в за-
         висимости от установки переключателей VGA.
             Есть небольшое изменение в стандартном MDA режиме 7,  тексто-
         вом  режиме,  с EGA.  Это изменение заключается в добавлении нес-
         кольких видеостраниц. Оригинальный монохромный адаптер использует
         только одну страницу. EGA может хранить до 8 отдельных видеостра-
         ниц в  зависимости от объема памяти EGA.  Номер страницы определя-
         ется в регистре ВН микропроцессора 80х86 при использовании тексто-
         вых функций BIOS.  Более старое программное обеспечение использует
         регистр ВН для других данных или терпит неудачу  при  попытке  его
         инициализации,  поэтому  окончательный текст может не появиться на
         нужной странице.
             EGA-совместимые карты прочих производителей  могут предложить
         Hercules-совместимый  графический  режим при использовании  моно-
         хромного дисплея. Два режима для монохромного дисплея приведены в
         таблице 9-3.

                                                         Таблица 9-3
                     Использование EGA c монохромным монитором
         ────┬────────┬────────┬────────┬───────┬────────┬─────┬───────
         Но- │ Тип    │ Макси- │ Размер │ Размер│ Макси- │Сег- │Разре-
         мер │        │ мальное│(столбцы│ прямо-│ мальное│мент │шение
         ре- │        │ число  │ х      │ уголь-│ число  │бу-  │
         жима│        │ цветов │ строки)│ ника  │ страниц│фера │
         ────┼────────┼────────┼────────┼───────┼────────┼─────┼───────
          7  │ Текст  │   4    │ 80х25  │ 9х14  │ 4/8*   │В000 │720х350
         15  │ Графика│   4    │ 80х25  │ 8х14  │ 1/2*   │А000 │640х350
         ────┴────────┴────────┴────────┴───────┴────────┴─────┴───────
         (*) - Зависит от объема установленной памяти EGA

             Для использования с VGA IBM  предоставляет  как  монохромные,
         так и цветные аналоговые мониторы. VGA можно установить таким об-
         разом,  что она может трактовать аналоговый монитор как  цифровой
         монохромный  монитор  или  как цифровой цветной монитор.  Другими
         словами, VGA может быть установлена так, что она может трактовать
         цветной  аналоговый  монитор как цифровой монохромный монитор,  и
         монохромный аналоговый монитор как цифровой монохромный монитор с
         высокой разрешающей способностью.  Эта возможность существует для
         обратной совместимости с EGA и,  при установке для работы  в  ка-
         честве EGA с монохромным монитором, свойства VGA не отличаются от
         свойств EGA с подключенным монохромным текстовым монитором.
             Программа самотестирования  при включении питания настраивает
         карту VGA для работы после загрузки  персонального  компьютера  в
         качестве либо монохромного адаптера, либо цветного адаптера. Пос-
         ле установки в качестве монохромного адаптера доступны только ви-
         деорежимы, перечисленные в таблице 9-3. После установки в качест-
         ве цветного адаптера доступны видеорежимы, указанные в табл. 9-4.


                                      - 9-5 -
                                                         Таблица 9-4
                             Аналоговый монитор и VGA,
                       конфигурированная для цветного режима
         ────┬────────┬────────┬────────┬───────┬────────┬────┬────────
         Но- │        │ Макси- │ Размер │ Размер│ Макси- │Сег-│ Разре-
         мер │   Тип  │ мальное│(столбцы│ прямо-│ мальное│мент│ шение
         ре- │        │ число  │ х      │ уголь-│ число  │бу- │
         жима│        │ цветов │ строки)│ ника  │ страниц│фера│
         ────┼────────┼────────┼────────┼───────┼────────┼────┼────────
          0  │ Текст  │   16   │ 40х25  │ 9х16  │   8    │В800│ 360х400
             │        │из 256К │        │       │        │    │
          1  │ Текст  │   16   │ 40х25  │ 9х16  │   8    │В800│ 360х400
             │        │из 256К │        │       │        │    │
          2  │ Текст  │   16   │ 80х25  │ 9х16  │   8    │В800│ 720х400
             │        │из 256К │        │       │        │    │
          3  │ Текст  │   16   │ 80х25  │ 9х16  │   8    │В800│ 720х400
             │        │из 256К │        │       │        │    │
          4  │ Графика│    4   │ 40х25  │ 8х8   │   1    │В800│ 320х200
          5  │ Графика│    4   │ 40х25  │ 8х8   │   1    │В800│ 320х200
          6  │ Графика│    2   │ 80х25  │ 8х8   │   1    │В800│ 640х200
         13  │ Графика│   16   │ 40х25  │ 8х8   │   8    │А000│ 320х200
             │        │из 256К │        │       │        │    │
         14  │ Графика│   16   │ 80х25  │ 8х8   │   4    │А000│ 640х200
             │        │из 256К │        │       │        │    │
         16  │ Графика│   16   │ 80х25  │ 8х14  │   2    │А000│ 640х350
             │        │из 256К │        │       │        │    │
         17  │ Графика│    2   │ 80х30  │ 8х16  │   1    │А000│ 640х480
             │        │из 256К │        │       │        │    │
         18  │ Графика│   16   │ 80х30  │ 8х16  │   1    │А000│ 640х480
             │        │из 256К │        │       │        │    │
         19  │ Графика│   256  │ 40х25  │ 8х8   │   1    │А000│ 320х200
             │        │из 256К │        │       │        │    │
         ────┴────────┴────────┴────────┴───────┴────────┴────┴────────


                    Соображения по установке и проверка наличия

             Возможности EGA зависят от типа монитора и объема  памяти  на
         плате EGA. Тип монитора определяет, какой видеорежим использовать
         для графики или текста,  а объем памяти EGA определяет число  до-
         ступных цветов и страниц.  Для Ваших программ очень важно узнать,
         имеется ли в персональном компьютере в наличии EGA,  до того, как
         Вы попытаетесь ее использовать, а также тип применяемого монитора
         и объем доступной памяти.  Это делает  программа,  приведенная  в
         листинге 9-1.  Байт 0х40:0х87 преобразует информацию о конфигура-
         ции EGA,  памяти и мониторе.  Этот байт является одним из  байтов
         состояния,  которые EGA BIOS содержит для внутреннего использова-
         ния и обеспечения программ необходимой им информацией.
             Мы интересуемся  битами 5 и 6,  которые показывают полную па-
         мять EGA;  битом 3,  который показывает, является ли EGA активным
         дисплеем;  и битом 1, который указывает тип используемого монито-
         ра.
             Функция также  вызывает один из новых вызовов BIOS EGA,  аль-
         тернативную функцию 10,  которая возвращает информацию  EGA.  EGA
         вызывается  помещением  0х12 в регистр АН и 0х10 в регистр BL,  а
         также использованием прерывания 10h. Вызов EGA BIOS содержит сле-
         дующую информацию:

                                      - 9-6 -

                           Возвращаемая информация о EGA

             Результат:  Int 0x10
             Вызывается: AH = 0х12
                         для выбора альтернативных функций EGA
                         BL = 0x10
                         Альтернативная функция для информации EGA
             Возвращает: BH =  0 = Цветной монитор
                               1 = Монохромный монитор
                         BL =  Расшифрованная память EGA:
                               0 = 64К
                               1 = 128К
                               2 = 192К
                               3 = 256К
                         СН =  Биты признаков
                         CL =  Установки переключателей платы EGA

             Так как BIOS персонального компьютера  не  использует  видео-
         функцию  0х12,  этот вызов может быть использован в качестве про-
         верки наличия EGA.  BIOS персонального компьютера спокойно откло-
         нит   неизвестное  ей  прерывание  10h  и  не  изменит  состояния
         регистров.  Таким образом,  если выходящие регистры не изменяются
         вызовом или входящие регистры не соответствуют данным о байте ин-
         формации EGA, значит EGA отсутствует. Если EGA имеется в наличии,
         то  тип используемого монитора определяется считыванием положения
         установочных переключателей.  Вы предполагаете,  что пользователь
         правильно  установил  переключатели  и их положение соответствует
         типу монитора.
             После обнаружения  EGA  функция проведет тестирование системы
         на наличие карты VGA. Большинство регистров EGA только записывае-
         мые,  в то время как в VGA они являются считываемыми/записываемы-
         ми. Регистр устанавливается в определенное значение и затем дела-
         ется  попытка  считать  это  значение.  Если  считанный  байт  не
         соответствует записанному,  то имеющаяся карта - EGA, в противном
         случае - VGA. Используемый регистр является регистром маски бита,
         который далее будет детально рассмотрен.
             Программа EGACHECK.C,  приведенная в листинге 9-1,  выполняет
         проверку активной карты EGA. (В системе может присутствовать дру-
         гая дисплейная карта. Если активна другая карта, то бит 3 байта 0
         х40:0х87 будет иметь значение 1). Если обнаружена активная  карта
         EGA, то сохраняется информация об установке.
             Макрокоманда PEEK_BYTE(seg,off),  представленная  в  листинге
         9-1, позволяет выбирать байт из любого места памяти персонального
         компьютера.  Макрокоманда работает путем сдвига значения сегмента
         влево  на  одно слово (16 бит) с последующим логическим сложением
         бита смещения для формирования длинного прерывания.  Это прерыва-
         ние затем сбрасывается в указатель far.

                         Листинг 9-1. Программа EGACHECK.C

         ----------------------------------------------------------------

         /* egacheck.c */
         /* Проверяет наличие карты EGA или VGA */
         /* При нахождении одной из них, информация сохраняется */
         #include <conio.h>

                                      - 9-7 -
         #include <dos.h>
         #include <stdio.h>

         #define PEEK_BYTE(seg,off) \
              (*(char far *) ( (long)(seg)<<16 | (off) ) )

         struct Ega_info     /* для хранения информации о EGA */
         {
           char card ;       /* для хранения типа карты */
           char monitor ;    /* для хранения типа монитора */
           int memory ;      /* объем памяти: 64, 128, 192, 256К */
           char high_res_graphics ;
           char text_mode ;
         }  ;

         int get_ega_info(struct Ega_info *) ;

         main()
         {
         struct Ega_info info ;

         if(get_ega_info(&info))   /* тест на наличие EGA */
          {
          if(info.card == 'E')
            {
            printf("\n\nИспользуется EGA.") ;
            printf("\nПодключена к") ;
            switch(info.monit)
            {
              case 'C': puts(" цветному монитору") ;
                        break ;
              case 'M': puts(" монохромному монитору") ;
                        break ;
              case 'H': puts("усовершенствованному цветному монитору");
                        break ;
              default:  break ;  /* не определен */
            }
            printf("n\%K байт памяти EGA.", info.memory);
            }
            else
               printf("\n\nИспользуется VGA.") ;
            printf("\nРежим %#2i - графика с высоким разрешением.",
                  (int)info.high_res_graphics) ;
            printf("\nРежим %#2i - текстовый режим.\n\n",
                  (int)info.text_mode) ;
          }
         else
          puts("\nНет активного EGA.") ;
         }                               /* конец main() */


         int get_ega_info(info)
         struct Ega_info *info ;

         /* Эта функция проверяет, есть ли в системе активный EGA */
         {
         union REGS regs ;

                                      - 9-8 -
         int i, test_mask = 1 ;
         /* Принять байт информации EGA из области данных BIOS */
            char bios_info = PEEK_BYTE(0x40,0x87) ;

            /* Бит 3 показывает, активный EGA или нет
             * если нет, то проверить наличие */
            if(bios_info & 0x8)
               return (0) ; /* если бит 3 = 1, EGA не активный */

            regs.h.ah = 0x12 ; /* альтернативная функция BIOS EGA */
            regs.h.bl = 0x10 ; /* получить информацию */
            regs.h.bh = 0xFF ; /* не возможное значение */
            int86(0x10, &regs, &regs) ; /* видео вызов EGA BIOS */

         /* bios_info биты 5 + 6 и BL(расшифрованная память EGA) и */
         /* bios_info бит 1 и ВН должны быть равны для EGA */
         if((regs.h.bl != ((bios_info & 0x60) >> 5 || /* память */
            (regs.h.bh != ((bios_info & 0x2) >> 1  || /* монитор */
            (regs.h.bh == 0xFF))            /* ВН должен изменить*/
           /* EGA есть, сохранить тип монитора */
           /* Код тип монитора:
                'C' для цветного,
                'M' для монохромного,
                'H' для hercules */
          switch(regs.h.cl) /* cl имеет установку переключателей EGA */
          {
             case 0: /* первоначально моно, EGA цветной 40х25 */
             case 6: /* моно второй, EGA цветной 40х25 */
                    info->monitor = 'C' ;
                    info->high_res_graphics = 0xD ;
                    info->text_mode = 0x1 ;
                    break ;
             case 1:  /* первоначально моно, EGA цветной 80х25 */
             case 2:  /* то же, что 1 */
             case 7:  /* моно второй, EGA цветной 80х25 */
             case 8:  /* то же, что 7 */
                    info->monitor = 'C' ;
                    info->high_res_graphics = 0xD ;
                    info->text_mode = 0x3 ;
                    break ;
             case 3: /* первоначально моно, EGA с высоким разрешением */
             case 9: /* сначала EGA с высоким разрешением, потом моно */
                    info->monitor = 'H' ;
                    info->high_res_graphics = 0x10 ;
                    info->text_mode = 0x3 ;
                    break ;
             case 4:  /* сначала 40 цветной, EGA моно */
             case 5:  /* сначала 80 цветной, EGA моно */
             case 10: /* сначала EGA моно, затем 40 цветной */
             case 11: /* сначала EGA моно, затем 80 цветной */
                    info->monitor = 'M' ;
                    info->high_res_graphics = 0xF ;
                    info->text_mode = 0x7 ;
                    break ;
             default: /* зарезервированные установки переключателей */
             return (0) ;
          }

                                      - 9-9 -
          info->memory = 64 * (regs.h.bl + 1) ;

          /* Различить EGA и VGA: */
          /* Это выполняется посредством записи значения в только
             считываемый регистр в EGA, но считываемый/записываемый
             в VGA */
         outp(0x3CE, 8) ;         /* маска бита EGA/VGA */
         outp(0x3CF, test_mask) ; /* направить значение теста */
         outp(0x3CE, 8) ;         /* снова маска бита */
         if(inp(0x3CF) == test_mask)
            {
            info->card = 'V' ;    /* регистр можно считать */
            if(info->monitor != 'M')
               {
               info->high_res_graphics = 0x12 ;
               info->text_mode = 0x3 ;
               }
            /* Если подключено к монохромному, то значения уже
             * установлены.
             */
            }
         else
            info->card = 'E' ; /* EGA */
         outp(0x3CE, 8) ;      /* сбросить маску бита */
         outp(0x3CF, 0xFF) ;
         /* В этой системе активен EGA/VGA, вернуть память */
         return(info->memory) ;
         }
         ---------------------------------------------------------------

             В новый заглавный файл, названный ega.h, должны быть добавле-
         ны  прототип  функции get_ega_info() и скелет структуры Ega_info.
         Эти функция и скелет будут использованы в последующих примерах.
             Теперь мы знаем,  какой режим надо использовать для графики и
         можем изобразить что-нибудь на дисплее.  EGA BIOS,  также  как  и
         BIOS  персонального компьютера имеет вызов Write Dot (писать точ-
         ку).  Этот вызов работает медленно, но очень полезен во всех гра-
         фических картах IBM. Вот некоторые характеристики вызова EGA BIOS
         Write Dot:

             Write Dot

             Результат:  Int 0x10

             Вызывается: АН =  0хС для выбора функции Write Dot
                         BH =  Страница
                         DX =  Номер строки
                         СХ =  Номер столбца
                         AL =  Значение цвета

             Возвращает: Ничего

             Обратите внимание на добавление в ВН номера страницы. Если Вы
         преобразуете  старое программное обеспечение для работы с EGA, то
         убедитесь, что номер страницы находится в ВН перед вызовом преры-
         вания  10h.  Программы,  написанные для монохромного адаптера или

                                      - 9-10 -
         CGA в графическом режиме,  наиболее чувствительны к этому  недос-
         татку.
             Вызов BIOS для переключения в графический режим  точно  такой
         же,  как и функция 0 прерывания 10h персонального компьютера. Тем
         не менее, BIOS не выполняет проверку на предмет того, не повредит
         ли выбранный Вами режим Ваш монитор. Монохромный монитор, подклю-
         ченный к EGA, может быть поврежден сигналом режима цветного текс-
         та или графики,  поэтому важно проверить совместимость монитора и
         режима работы.  В программе 9-1 функция  get_ega_info(&info)  ис-
         пользуется  для  проверки монитора и нахождения безопасного в ис-
         пользовании режима работы  с  высокой  разрешающей  способностью.
         Программа, представленная в листинге 9-2, демонстрирует использо-
         вание функции set_crt_mode() для установки графического  режима и
         использование  dot(),  которая  применяет функцию BIOS Write Dot.
         Эта программа начертит серию параллельных диагональных линий.

                         Листинг 9-2. Программа DIAGONAL.C
         ---------------------------------------------------------------

         /* diagonal.c */
         /* Демонстрирует графический режим с высоким разрешением */
         #include <conio.h>
         #include <dos.h>
         #include <stdio.h>

         void set_crt_mode( char ) ;   /* добавить это в "ega.h" */
         void dot( int, int, int, int ) ;

         main()
         {
           registr i,j ;
           struct Ega_info info ;
           if(get_ega_info(&info))
              set_crt_mode(info.high_res_graphics);
           else
              return(1) ;

           for(j = 0; j <= 500; j += 5)
           for(i = 0; i <= 100; ++i)
               dot(i,i+j,13,0) ;
           getch() ;   /* ожидать символ, который надо изобразить */
           set_crt_mode(info.text_mode) ;
           return(0) ;
         }

         /*==========================================================*/
         void dot(row,col,color,page)
         int row, col, color, page;
         {
            union REGS regs ;
            regs.x.dx = row ;
            regs.x.cx = col ;
            regs.h.al = (char)color ;
            regs.h.ah = (char)0xC ;      /* Вызов Write Dot */
            regs.h.bh = (char)page ;
            int86(0x10, &regs, &regs) ;
         }

                                      - 9-11 -

         /*==========================================================*/
         void set_crt_mode(mode)
         char mode ;
         {
           union REGS regs ;
           regs.h.al = mode ;         /* al = установить режим */
           regs.h.ah = (char)0 ;      /* Функция "установить режим" */
           int86(0x10, &regs, &regs); /*Выполнить прерывание BIOS 10h*/
         }
         /*==========================================================*/

         ---------------------------------------------------------------


             Как только Вы увидите,  как медленно  работает  функция  BIOS
         Write Dot,  то,  вероятно, спросите, можно ли ускорить ее работу.
         Реализация этого требует обхода EGA BIOS  и  помещения  элементов
         изображения непосредственно в память EGA.  Тем не менее,  сначала
         Вы должны понять,  каким образом организована память EGA,  и  то,
         как можно ею управлять.


                                Организация памяти

             Для графики EGA использует два различных  способа организации
         памяти дисплея.  В режимах с 4 по 6 EGA использует такую же орга-
         низацию памяти,  что и CGA. В этих режимах сегмент памяти дисплея
         начинается в 0хВ800 и использует 80 битов на каждую строку скани-
         рования (линию развертки). Так как линий развертки 200, использу-
         ется  16,000  байтов.  В  режиме  средней разрешающей способности
         320х200, каждый  байт представляет 4 элемента изображения с одним
         из четырех цветов,  или два бита на элемент изображения. В режиме
         6 каждый байт представляет 8 элементов изображения с двумя цвета-
         ми,  или один бит на элемент изображения. Если бит имеет значение
         0,  то соответствующий элемент изображения выключен.  Кроме того,
         четные линии развертки расположены в первых 8К дисплейной памяти,
         а  нечетные  занимают вторые 8К памяти.  Разделенная память линий
         развертки требует тестирования каждого смещения элемента  изобра-
         жения для определения того, четное оно или нечетное.
             Дисплейная память  режимов с 13 по 16 (по режим 18 VGA) начи-
         нается с сегмента 0хА000 и использует до 64К адресного пространс-
         тва  центрального  процессора  80х86.  Каждый байт представляет 8
         элементов изображения,  причем самый значимый бит расположен пер-
         вым слева.  Линии развертки не разделены в памяти,  как в режимах
         CGA, поэтому смещение байта элемента изображения проще в вычисле-
         нии.  В  режиме 16 EGA имеет максимальную разрешающую способность
         640 х 350,  или 224,000 элементов изображения. Так как имеется до
         16 цветов,  каждый элемент изображения должен использовать 4 бита
         для определения цвета.  Все вместе это  составляет  использование
         общей памяти, равной (640 х 350 элементов изображения / 8 элемен-
         тов изображения на байт х 4 бита на элемент изображения) 109К.
             Центральный процессор   80х86,   применяемый  в  персональном
         компьютере РС,  может адресовываться только  к  сегменту  объемом
         64К.  EGA приспосабливается к 64К сегментному пределу путем деле-
         ния 128К из ее 256К памяти на четыре битовые матрицы объемом 32К.
         Каждая  битовая матрица (или битовый массив) соответствуют одному

                                      - 9-12 -
         биту цвета элемента изображения.  Представьте,  что  эти  битовые
         матрицы  сложены друг на друга по одному адресу центрального про-
         цессора.  Каждый  адрес  дисплейной  памяти реально  представляет
         4 байта памяти EGA.
             В режимах VGA 17 и 18 организация памяти EGA просто  расширя-
         ется на следующие 130 линий развертки. VGA имеет режим разрешения
         320 х 200 с 256 цветами.  Позже этот режим будет  рассмотрен  от-
         дельно.

                                 Регистры-защелки

             Чтение или запись 4 различных байтов (одного для каждой бито-
         вой матрицы) по одному адресу  центрального  процессора  является
         проблемой. Для ее преодоления EGA имеет четыре  регистра-защелки.
         Регистры-защелки EGA временно сохраняют 1 байт из каждого из  че-
         тырех  битовых  матриц.  Логическая схема EGA заполняет каждый из
         четырех регистров-защелок байтом каждой битовой матрицы по  адре-
         су, который центральный процессор считал последним.  Когда  цент-
         ральный  процессор посылает байт по последнему считанному адресу,
         содержание каждого из четырех регистров может  остаться  неизмен-
         ным,  модифицироваться  или быть полностью заменено данными цент-
         рального процессора.  Содержание регистра-защелки  затем  пишется
         обратно в каждую из битовых матриц EGA.
             После обратной  записи содержания регистров-защелок в битовые
         матрицы EGA,  регистры снова "складируются",  сохранив  один  бит
         каждого  из  четырех  байтов,  формируя 4-битовый цвет для восьми
         элементов изображения. Взаимоотношения между  регистрами-защелка-
         ми и битовыми матрицами проиллюстрированы на рисунке 9-1, который
         демонстрирует состояние памяти EGA и содержание четырех регистров
         -защелок после считывания центральным процессором байта по адресу
         А000:0000.  Восемь элементов изображения в байте содержат цвета с
         0 по 7.
             Важно понять,  что байт, возвращенный центральным процессором
         после чтения А000:0000, не используется. Этот байт только читает-
         ся для установления того,  с какими элементами изображения  рабо-
         тать (в данном случае,  элементы изображения с 0 по 7 в строке 0)
         и для "подготовки" регистров-защелок,  позволяющих  данным  цент-
         рального процессора  манипулировать  отдельными  байтами  битовых
         матриц.   Это  позволяет  центральному  процессору  персонального
         компьютера модифицировать,  заменять или очищать восемь элементов
         изображения,  содержащихся в четырех байтах. Для работы с элемен-
         тами изображения в другой строке или столбце, происходит смещение
         с  A000 и центральный процессор считывает новый байт,  содержащий
         элементы изображения.
             Установка нескольких  управляющих регистров EGA влияет на то,
         что центральный  процессор  модифицирует,  заменяет или оставляет
         неизменными регистры-защелки. Доступ к этим регистрам осуществля-
         ется посредством одного из пяти индексированных чипов  сверхболь-
         ших  интегральных схем (СБИС) на плате EGA.  Установка чипов СБИС
         происходит направлением номера индекса,  соответствующего необхо-
         димой функции, одному из внутренних регистров EGA, и следующей за
         номером информацией для этой функции.  Существенно то, что индекс
         соответствует одному из многих внутренних регистров EGA,  но этот
         регистр связан с единственным портом вывода персонального  компь-
         ютера.  Данные для этих регистров направляются при помощи команды

                                      - 9-13 -
                    ┌─┬─┬─┬─┬─┬─┬─┬─┬──────────┐   
                    │0│0│0│0│0│0│0│0│ Битовая  │   │
                    ├─┴─┴─┴─┴─┴─┴─┴─┘ матрица 3│   │   Регистры - защелки
                  ┌─┼─┬─┬─┬─┬─┬─┬─┬──────────┐ │   │    ┌─┬─┬─┬─┬─┬─┬─┬─┐
                  │0│0│0│0│1│1│1│1│ Битовая  │ │        │0│0│0│0│0│0│0│0│ 3
                  ├─┴─┴─┴─┴─┴─┴─┴─┘ матрица 2│ │   Ц    └─┴─┴─┴─┴─┴─┴─┴─┘
                ┌─┼─┬─┬─┬─┬─┬─┬─┬──────────┐ │ │        ┌─┬─┬─┬─┬─┬─┬─┬─┐
                │0│0│1│1│0│0│1│1│ Битовая  │ │ │   В    │0│0│0│0│1│1│1│1│ 2
                ├─┴─┴─┴─┴─┴─┴─┴─┘ матрица 1│ │ │        └─┴─┴─┴─┴─┴─┴─┴─┘
              ┌─┼─┬─┬─┬─┬─┬─┬─┬──────────┐ │ │ │   Е    ┌─┬─┬─┬─┬─┬─┬─┬─┐
     A000:0000│0│1│0│1│0│1│0│1│ Битовая  │ │ ├─┘        │0│0│1│1│0│0│1│1│ 1
              ├─┴─┴─┴─┴─┴─┴─┴─┘ матрица 0│ │ │     Т    └─┴─┴─┴─┴─┴─┴─┴─┘
              │                          │ ├─┘          ┌─┬─┬─┬─┬─┬─┬─┬─┐
              │                          │ │       │    │0│1│0│1│0│1│0│1│ 0
              │                          ├─┘       │    └─┴─┴─┴─┴─┴─┴─┴─┘
              │                          │         │     Позиции пикселей
              └──────────────────────────┘         


                  Рис.9-1. Битовые матрицы и регистры-защелки EGA


         OUT процессора 80х86 или библиотечной функции языка Си outp().
             Например, EGA  имеет регистр битовой маски,  который защищает
         от изменения отдельные биты регистров-защелок.  Установка в  этом
         регистре бита в 0 маскирует соответствующий бит в регистре-защел-
         ке,  а установка в 1 разрешает изменять бит записью данных  цент-
         ральным процессором.  Кроме того, регистр битовой маски позволяет
         изменять отдельные элементы  изображения  без  изменения  смежных
         элементов изображения, адресуемых битом.
             Регистр битовой маски имеет номер функции 8 в графическом чи-
         пе  1  и 2 EGA.  Он программируется направлением индекса 8 в порт
         0х3СЕ и данных маски бита в порт 0хCF.  Следующие операторы языка
         Си установят  регистр маски бита для защиты всех битов, кроме би-
         та 2:

         outp(0x3CE, 8) ;      /* индекс маски бита */
         outp(0x3CF, 0x2) ;    /* все биты, кроме 2, в 0 */

         Но эти операторы не дают ключ к разгадке,   кроме комментирования
         того, что они делают. Чуть дальше  мы рассмотрим макрокоманду Си,
         с помощью которой проще установить регистры EGA.
             Вторым регистром EGA,  влияющим на перезапись содержания  ре-
         гистра-защелки, является регистр маски матрицы. Если любой из че-
         тырех битов этого регистра нулевой,  соответствующие битовые мат-
         рицы  (битовые массивы) защищены от изменения.  Направление числа
         между 0 и 15 в регистр маски матрицы запишет  в  битовые  матрицы
         EGA цвет,  соответствующий этому числу. Тем не менее, прежнее со-
         держание битовых массивов не стирается.  Оно должно  быть  стерто
         перед  установкой  нового значения цвета маски матрицы,  но после
         установки маски бита,  записью нуля в байт, содержащий изменяемый
         элемент  изображения.  Регистр маски матрицы является частью чипа
         планировщика EGA. Он доступен посредством направления индекса 2 в
         порт  0х3С4  и  направлением маски матрицы в порт 0х3С5.  Влияние
         маски бита и маски матрицы проиллюстрировано на рисунке 9-2.



                                      - 9-14 -




        ┌─┐  ┌─┬─┬─┬─┬─┬─┬─┬─┐              ┌─┬─┬─┬─┬─┬─┬─┬─┬──────────┐
     ┌──┤1├──┤ │ │1│ │ │ │ │ ├──────────────┤ │ │1│ │ │ │ │ │ Битовая  │
     │  └─┘  └─┴─┴─┴─┴─┴─┴─┴─┘              ├─┴─┴─┴─┴─┴─┴─┴─┘ матрица 3│
     │  ┌─┐  ┌─┬─┬─┬─┬─┬─┬─┬─┐            ┌─┼─┬─┬─┬─┬─┬─┬─┬──────────┐ │
     ├──┤1├──┤ │ │1│ │ │ │ │ ├────────────┤ │ │1│ │ │ │ │ │ Битовая  │ │
     │  └─┘  └─┴─┴─┴─┴─┴─┴─┴─┘            ├─┴─┴─┴─┴─┴─┴─┴─┘ матрица 2│ │
     │  ┌─┐  ┌─┬─┬─┬─┬─┬─┬─┬─┐          ┌─┼─┬─┬─┬─┬─┬─┬─┬──────────┐ │ │
     ├──┤0├──┤ │ │ │ │ │ │ │ ├──────────┤ │ │ │ │ │ │ │ │ Битовая  │ │ │
     │  └─┘  └─┴─┴─┴─┴─┴─┴─┴─┘          ├─┴─┴─┴─┴─┴─┴─┴─┘ матрица 1│ │ │
     │  ┌─┐  ┌─┬─┬─┬─┬─┬─┬─┬─┐        ┌─┼─┬─┬─┬─┬─┬─┬─┬──────────┐ │ │ │
     ├──┤1├──┤ │ │1│ │ │ │ │ ├────────┤ │ │1│ │ │ │ │ │ Битовая  │ │ ├─┘
     │  └─┘  └─┴─┴─┴─┴─┴─┴─┴─┘        ├─┴─┴─┴─┴─┴─┴─┴─┘ матрица 0│ │ │
     └──────────────┐                 │                          │ ├─┘
                 ┌─┬┴┬─┬─┬─┬─┬─┬─┐    │                          │ │
                 │0│0│1│0│0│0│0│0│    │                          ├─┘
                 └─┴─┴─┴┬┴─┴─┴─┴─┘    │                          │
                 ┌─┬─┬─┬┴┬─┬─┬─┬─┐    └──────────────────────────┘
                 │1│1│1│1│1│1│1│1│
                 └─┴─┴─┴─┴─┴─┴─┴─┘

                  Рис.9-2. Регистры битовой маски и маски матрицы


                              Прямая запись на экран

             Зная о  регистрах  маски бита и маски матрицы,  а также о ре-
         гистрах-защелках EGA, мы имеем достаточно информации для создания
         программы на языке Си,  которая пишет точку непосредственно в эк-
         ранную память. Эта программа работает быстрее, чем аналогичная ей
         программа  BIOS  адаптера  EGA.  При  работе с 8-МГц персональным
         компьютером АТ, EGA BIOS поместит на дисплей в течении 1 миллисе-
         кунды  2.56  точки (2.56 точек/мс).  Программа,  представленная в
         листинге 9-3,  помещает на дисплей 7.55 точек/ мс - скорость воз-
         растает на 185 процентов.  Недостатком является то, что fastdot()
         может работать только в графических режимах EGA,  и  для работы с
         другой дисплейной картой  необходимо переписать программу.
             Следующие макрокоманды позволят программе 9-3 установить мас-
         ку  бита,  маску  матрицы,  а  также  другие внутренние регистры.
         #define EGA_GRFX(index, value) { outp(0X3CE, index) ; \
                                          outp(0x3CF, value) ;}
         #define EGA_SQNC(index, value) { outp(0X3C4, index) ; \
                                          outp(0x3C5, value) ;}

             Первая макрокоманда,  EGA_GRFX, принимает в качестве аргумен-
         тов номер индекса,  соответствующего функции,  выбранной из  чипа
         контроллера графики 1 и 2,  а также  значение, направляемое чипу.
         Графические чипы 1 и 2 EGA управляют доступом к битовым массивам.
         (Тем не менее,  они реально представляют собой два чипа, располо-
         женные по одному адресу,  и могут считаться одним  чипом.)  Адрес
         индекса графических чипов 1 и 2 0x3CE, а адрес данных 0x3CF. Мак-
         рокоманда охватывает два оператора языка Си.  Первый оператор по-
         сылает чипам значение индекса, а второй оператор посылает данные.
             Вторая  макрокоманда,  EGA_SQNC,  сходна  с EGA_GRFG. Однако,

                                      - 9-15 -
         EGA_SQNC имеет доступ к другому чипу, чипу планировщика EGA, нап-
         равляя индекс и данные различным портам вывода.  Наибольший инте-
         рес для чипа планировщика представляет регистр маски матрицы.
              Следующие две макрокоманды дают подпрограмме доступ к адресу
         сегмент:смещение  в любом месте адресного пространства персональ-
         ного компьютера:

         #define PEEK_BYTE(s,o) (*(char far *) ( (long)(s)<<16 | (o) ))
         #define PEEK_WORD(s,o) (*(int far *) ( (long)(s)<<16 | (o) ))

             Заключительные макрокоманды комбинируют предыдущие.  Макроко-
         манда GET_CRT_COLS() возвращает значение для использования в  ка-
         честве числа битов на линию в графических режимах EGA.  Число би-
         тов на линию равно числу символов на линию, и это число  является
         адресом   0x40:0x4A   в   области   данных   BIOS.   Макрокоманды
         EGA_BIT_MASK и EGA_MAP_MASK устанавливают соответственно регистры
         маски бита и маски матрицы.

         #define GET_CRT_COLS()   PEEK_WORD(0x40, 0x4A)
         #define EGA_BIT_MASK(mask)   EGA_GRFX(8, mask)
         #define EGA_MAP_MASK(mask)   EGA_SQNC(2, mask)
             Вместе эти макрокоманды облегчают чтение  и  понимание  кодов
         программы,  написанной для манипулирования аппаратными средствами
         EGA.  Эти макрокоманды далее используются во всех программах этой
         главы.
             Большинство регистров EGA доступны только для  записи. Каждая
         программа, использующая дисплей, нуждается в информации о состоя-
         нии EGA, так как только записываемые регистры нельзя считать. По-
         этому, самым безопасным состоянием регистров EGA является состоя-
         ние EGA BIOS,  установленное по умолчанию.  Кроме того,  EGA BIOS
         предполагает, что при записи символов на дисплей регистры EGA на-
         ходятся в состоянии,  установленном по  умолчанию.  Если  регистр
         маски бита установлен в состояние маскировки бита,  символы будут
         нечитаемыми.  Для маски бита и маски матрицы состоянием, установ-
         ленным по умолчанию,  является выключенный режим маскировки, поэ-
         тому,  установка  маски  0xF  и  0xFF  в  последних  двух строках
         fastdot() восстанавливает состояние по  умолчанию.  Преимуществом
         регистров  VGA  является то,  что они доступны и для чтения и для
         записи.  (Различия между EGA и VGA были использованы в  программе
         EGACHECK.C  для  обнаружения  карты  VGA.) Поэтому,  регистры VGA
         должны быть оставлены в состоянии по умолчанию.
             Убедитесь, что Вы понимаете,  как  вычисляется  в  программе,
         приведенной в листинге 9-3, адрес байта элемента изображения:

         char far *rgen = (char far *)(0xA0000000L +
                          (col >> 3) +
                          (row * GET_CRT_COLS()) );

         Адрес бита  вычисляется как ((строка х байты на строку) + столбцы
         / 8 бит на байт). В целях повышения скорости деления колонок на 8
         используется оператор правого сдвига языка Си, >>.

                         Листинг 9-3. Программа FASTDOT.C
         ---------------------------------------------------------------

         /* fastdot.c */
         #include <conio.h>

                                      - 9-16 -

         fasdot(row, col, color)
         /* Эта программа поместит точку в буфер дисплейной памяти EGA
         ** Использовать только в графических режимах EGA (13, 14, 15
         ** или 16) и с памятью EGA от 128К
         ** ИЛИ с VGA в режимах 13, 14, 15, 16, 17 или 18
         */
         int  row, col, color;
         {
         char latch ;
         /* Установить адрес изменяемого байта */
         /* Байт буфера = А000:((строка*байтов/строка)+столбец/8) */
           unsigned char far *rgen = (char far *)(0xA0000000L +
                                     (col >> 3)  +
                                     (row * GET_CRT_COLS()) ) ;
         /* Вычислить изменяемый бит: */
           char bit_mask = (char)(0x80 >> (col & 7)) ;
           EGA_BIT_MASK(bit_mask) ;   /* установить маску бита */
           latch = *(rgen) ;          /* подготовить защелки */
           *(rgen) = 0 ;              /* очистить бит */
           EGA_MAP_MASK(color) ;      /* установить цвет */
           *(rgen) = 0xFF ;           /* установить бит */
           EGA_MAP_MASK(0xF) ;        /* сбросить маску матрицы */
           EGA_BIT_MASK(0xFF) ;       /* сбросить маску бита */
         }
         ---------------------------------------------------------------

         Для того, чтобы узнать число бит на строку, значение которого мо-
         жет быть равно 40 байтам в видеорежиме 13 или 80 байтам в режимах
         с 14 по 16, посмотрите на значение числа символов на строку в об-
         ласти данных BIOS (адрес 0х40:0х4А).  Число бит на строку и число
         символов  на  строку в графических режимах EGA одно и то же.  Ре-
         зультат всего вычисления добавляется к 0xA0000000L,  представляю-
         щим собой сегмент графических режимов EGA.  Полное значение затем
         сбрасывается в указатель far.
             Номер бита  в  байте,  соответствующем  изменяемому  элементу
         изображения, вычисляется как (col~&~7). Как только будет известен
         номер  бита,  маска бита устанавливается в значение 0х80 >> номер
         бита (0х80 - это 010000000b).
             Предыдущая  программа предполагает, что используется страница
         0. Для того, чтобы получить возможность адресации к странице, от-
         личной от 0, вставьте следующие строки:

         while(page){
          rgen += PEEK_WORD(0x40, 0x4C) ; /* добавить длину страницы */
          --page ;}

         где page  - номер адресуемой страницы.  Слово по адресу 0х40:0х4С
         содержит  длину в байтах дисплейного буфера,  используемого  под-
         программами EGA BIOS.
             Испытайте программу, приведенную в листинге 9-2, заменив опе-
         ратор  dot  оператором fastdot(). Она в два-три раза быстрее, чем
         подпрограмма BIOS.




                                      - 9-17 -
                                    Много точек

             Для достижения максимальной производительности уникальных ап-
         паратных средств EGA необходимо написать много функций. Например,
         подпрограмма fastdot() устанавливает маску бита и маску матрицы в
         требуемые значения в начале,  а затем в конце сбрасывает эти  ре-
         гистры  в  первоначальное  состояние BIOS.  Если функция вызывает
         подпрограмму fastdot неоднократно, сброс регистра в конце fastdot
         повторять необязательно. Это замедляет работу функции.
             Программа, представленная в листинге 9-4,  включает  подпрог-
         рамму  вычерчивания  линий,  основанную  на алгоритме Бресенгама.
         Этот алгоритм первоначально использовался для управления цифровы-
         ми плоттерами,  но он также приемлем для дисплейной графики с би-
         товыми матрицами. Алгоритм всегда увеличивается (или уменьшается)
         на  1  в направлении или X или Y.  Выбор направления X или Y осу-
         ществляется увеличением наклона линии.  Если подъем  (направление
         Y)  больше,  то  увеличивается  (или уменьшается) Y;  если прогон
         (направление X) больше,  то увеличивается  (или  уменьшается)  X.
         Увеличение  или уменьшение X или Y выбирается направлением линии.
         Термин "совокупная ошибка" используется при увеличении или умень-
         шении в перпендикулярном направлении.
             Вместо вызова подпрограммы fastdot(), точки помещаются непос-
         редственно  на  экран  дисплея.  Регистры EGA сбрасываются только
         один раз в конце и функция работает гораздо быстрее функции,  ос-
         нованной на вызове fastdot().

                           Листинг 9-4. Программа BRES.C
         ---------------------------------------------------------------

         /* bres.c */
         /* Чертит серию линий для демонстрации функции line() */
         #include <conio.h>
         #include <dos.h>
         #include <stdio.h>
         #include "ega.h"
         void line(int, int, int, int, int); /* добавить это в ega.h */

         main()
         {
           int x1, y1, x2, y2 ;
           int step = 10, color = 13, scan_lines ;
           struct Ega_info info ;

           if(get_ega_info(&info) >= 128  /* активный EGA? память? */
           {
             set_crt_mode(info.high_res_grahics) ;
             scan_lines = (PEEK_BYTE(0x40, 0x84) + 1)
                           * PEEK_WORD(0x40, 0x85) ;
             y2 = (scan_lines - 1) - ((scan_lines - 1) % step) ;
             for (y1 = 0, x1 = 0, x2 = 0;
                  y1 <= y2;
                  y1 += step, x2 += step)
                line(x1,y1,x2,y2,color) ;
             getchar() ;  /* ждать нажатия клавиши */
           set_crt_mode(info.text_mode);
           }
           else

                                      - 9-18 -
           puts("\nАдаптер EGA не активен или не установлен.\n") ;
         }

         void line(x1,y1,x2,y2,color)
         int x1,y1,x2,y2,color ;
         /* Быстрая функция линии - использует алгоритм Бресенгама */
         /* Координаты строк(Y) и столбцов(X) считаются не равными */
         #define sign(x) (((x) < 0) ? (-1) : (1))
         #define qabs(x) (((x) < 0) ? -(x) : (x))
         {
         int dx = qabs(x2 - x1) ; /* прогон */
         int dy = qabs(y2 - y1) ; /* подъем */
         int s1 = sign(x2 - x1) ; /* для увеличения/уменьшения */
         int s2 = sign(y2 - y1) ;
         int dx2, dy2, bytes_per_line = GET_CRT_COLS() ;
         registr error_term, i ;
         unsigned char far *rgen = (char far *)(0xA0000000L) ;
         unsigned char exchange = (char)0 ;

         /* Большее значение подъема или прогона определяет,
         ** что увеличивать в цикле
         */
         if(dy > dx)
           { int temp = dx; dx = dy; dy = temp; exchange = (char)1; }

           dx2=(dx << 1); /* использовать повторно, вычислить сейчас */
           dy2=(dy << 1);
           error_term=(dy - dx) << 1; /* инициализировать error_term */
           EGA_GRFX(0, color) ;  /* использовать регистр  EGA
                                    установить/сбросить */
           EGA_GRFX(1, 0xF) ;    /* разрешить все битовые массивы */
           for (i=1; i<=dx; ++i) /* все элементы изображения на линии */
           {
           EGA_BIT_MASK(0x80 >> (x1 & 7) ) ;
           rgen[ ((x1 >> 3) + (y1 * bytes_per_line)) ] += 0x1 ;
              while (error_term >= 0)  /* цикл до следующего элемента */
              {
               if (exchange)
                   x1 += s1 ;
               else
                   y1 += s2 ;
              error_term -= dx2 ;
              }
              if (exchange)
                   y1 += s2 ;
              else
                   x1 += s1 ;
              error_term += dy2 ;
           }
         EGA_GRFX(1, 0) ;   /* запретить регистр установить/сбросить */
         EGA_BIT_MASK(0xFF) ; /* сбросить маску бита */
         }
         ---------------------------------------------------------------

             Для хранения графического образа на экране  программа  должна
         знать  высоту  и  ширину дисплея в элементах изображения.  Ширина
         дисплея в элементах изображения указывается как  GET_CRT_COLS() x

                                      - 9-19 -
         х 8 элементов/байт. Высота должна быть точно определена из табли-
         цы, содержащей количество вертикальных линий развертки для каждо-
         го режима.  Однако,  это более быстрый, но менее точный способ. И
         число строк символов, и размер точки (байта на символ) можно зап-
         рограммировать, кроме того, любой из них можно изменить. Но высо-
         та прямоугольника для символа в байтах и  число  строк  развертки
         определяют  количество  строк.  Так как слово с адресом 0х40:0х85
         содержит байты на символ и байт с адресом 0:40х0:84 содержит  ко-
         личество строк,  они могут быть использованы для вычисления числа
         строк развертки для любого видеорежима. Оператор языка Си

         scan_lines = (PEEK_BYTE(0x40, 0x84) + 1)
                      * PEEK_WORD(0x40, 0x85) ;

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


                      Использование регистра установки/сброса

             В программе,  представленной в листинге 9-4,  функция  line()
         использует другой метод определения цвета точек на дисплее, неже-
         ли подпрограмма fastdot().  Подпрограмма fastdot() применяет  для
         определения  цвета  регистр маски бита.   Но  так как определение
         маски для регистра маски матрицы не очищает предыдущую  точку, то
         эта  точка  должна быть сначала сброшена при помощи установки ре-
         гистра маски бита в 0xF с последующей установкой цвета  для новой
         точки.  Другими словами,  для установки определенного цвета точки
         доступ и к маске матрицы,  и к памяти EGA должен быть осуществлен
         дважды.
             Функция line() использует регистр установки/сброса и для  оп-
         ределения цвета разрешает выполнить установку/сброс регистра. Ре-
         гистр установки/сброса установит байт в  0xFF  в  каждом  битовом
         массиве EGA,  бит которого в этом регистре равен единице, и сбро-
         сит байт в 0 в каждом битовом массиве,  бит которого равен  нулю.
         Следовательно, предыдущее содержание регистров-защелок заменяется
         номером цвета,  соответствующего значению,  установленному в  ре-
         гистре  установки/сброса.  Регистр маски матрицы не влияет на ре-
         гистр установки/сброса,  но регистр маски бита полезен для защиты
         смежных элементов изображения.
             Чтобы использовать регистр установки/сброса, Вы сначала долж-
         ны  разрешить его с помощью регистра разрешения установки/сброса.
         Регистр установки/сброса и  регистр  разрешения  установки/сброса
         являются  частью графического контроллера EGA.  Состояние BIOS по
         умолчанию для регистра разрешения установки/сброса  0,  это озна-
         чает,  что регистр установки/сброса выключен. Каждый бит из четы-
         рехбитового  значения, направляемого  регистру  разрешения  уста-
         новки/сброса, соответствует битовой матрице EGA. Если бит  в  ре-
         гистре разрешения  установки/сброса  0,  соответствующая  битовая
         матрица защищена от изменения регистром установки/сброса.
             Регистр установки/сброса доступен направлениям  индекса  0  в
         порт  0х3СЕ и последующим направлением четырехбитового кода цвета
         в порт 0x3CF.  Регистр установки/сброса оказывает влияние  только
         на  битовые  матрицы,  разрешенные  регистром разрешения установ-

                                      - 9-20 -
         ки/сброса. Регистр разрешения установки/сброса доступен направле-
         нием индекса 1 в порт 0х3СЕ с последующим направлением четырехби-
         товой маски матрицы в порт 0x3CF.
             Обратите внимание на оператор rgen[ ((x1 >> 3) + (y1 * bytes_
         per_line)) ]+@ 0x1 ;  в программе 9-4. Поскольку дисплейный буфер
         EGA  линейный,  к нему легко обратиться как к матрице.  Выражение
         внутри скобок вычисляет смещение буфера изменяемого байта.  Похо-
         же,  что правая сторона оператора прибавляет 1 к байту, что цент-
         ральный процессор и пытается проделать.  Тем не  менее,  действи-
         тельной    целью   является   предохранение   смежных   элементов
         изображения,  содержащихся в байте.  Когда  используется  регистр
         маски  бита,  необходимо сначала считать дисплейный буфер для за-
         полнения регистров-защелок таким образом,  чтобы  другие  биты  в
         этом  байте были защищены.  В отличие от метода установки цвета с
         помощью регистра маски бита, при использовании регистра установки
         /сброса байт,  посылаемый центральным процессором,  служит только
         для установки адреса изменяемого байта.
             Таким образом,  выражение +=1 выполняет две функции: оно счи-
         тывает дисплейный буфер в целях  установки  регистров-защелок,  а
         также возвращает байт, который включает регистр установки/сброса.
         В процессе трансляции компилятором языка Си  операции  в  команду
         процессора 80х86 1 может принимать любое значение, которое снача-
         ла считывает, а затем сохраняет байт в дисплейной памяти EGA.


                         Использование режимов записи EGA

             EGA имеет три режима записи: 0, 1 и 2. Изменение режима запи-
         си меняет реакцию аппаратных средств EGA на направление централь-
         ным процессором байта в дисплейный буфер. Каждый режим записи оп-
         тимизирован для различного использования. Режим записи 0 является
         режимом  записи  общего назначения,  режим записи 1 оптимизирован
         для копирования областей памяти EGA и режим  записи  2  наилучшим
         образом  используется  для закрашивания.  Изменение режима записи
         может существенно ускорить выполнение операции.
             Режим записи  0 является режимом,  применяемым EGA BIOS.  Это
         наиболее общий режим записи. В режиме 0 цвет элемента изображения
         может быть установлен с помощью как регистра маски матрицы, так и
         регистра установки/сброса. Регистр маски матрицы используется EGA
         BIOS и подпрограммой fastdot().  Функция line() применяет регистр
         установки/сброса для определения цвета. При использовании регист-
         ра  маски матрицы отдельные элементы изображения могут быть уста-
         новлены посылаемым центральным процессором байтом с соответствую-
         щими битами,  установленными в 1.  Тем не менее, смежные элементы
         изображения в байте должны быть защищены с помощью регистра маски
         бита.  При  применении регистра установки/сброса биты посылаемого
         центральным процессором байта не соответствуют элементам  изобра-
         жения. Байт записывается только для определения смещения изменяе-
         мых  элементов  изображения.  Цвет  определяется в регистре уста-
         новки/сброса, а регистр маски бита позволяет управлять отдельными
         элементами изображения.
             Режим записи  2  очень  похож  на режим записи 0.  В режиме 2
         байт,  посылаемый центральным процессором,  скорее  устанавливает
         цвет, чем отдельные элементы изображения. Регистр маски бита поз-
         воляет управлять отдельными элементами изображения  и,  если  ре-
         гистр  маски бита не установлен,  весь байт элементов изображения
         заполняется цветом, значение которого посылается центральным про-

                                      - 9-21 -
         цессором.  Режим записи определяется в битах 0 и 1 байта, направ-
         ляемого регистром режима графических чипов 1 и 2.  Регистр режима
         имеет индекс 5. Программа, приведенная в листинге 9-5, демонстри-
         рует режим записи 2.  Подпрограмма rect() использует режим 2  для
         заполнения прямоугольника заданным цветом.

                           Листинг 9-5. Программа RECT.C
         ---------------------------------------------------------------

         /* rect.c */
         /* Эта программа демонстрирует режим записи 2 */
         #include <conio.h>
         #include <dos.h>
         #include <stdio.h>
         #include "ega.h"

         void line(int,int,int,int,char); /* добавить это в ega.h */

         main()
         {
         int i,j;
         struct Ega_info info ;
         if(get_ega_info(&info))
            set_crt_mode(info.high_res_graphics) ;
         else
            return(1) ;
         printf("\nЦвет #:\n");
         for (i=0,j=0;i<16;++i,j+=40)
         {
            printf(" %2i  ",i);
            rect(50,j,349,j+39,(char)i);
         }
         getchar();
         set_crt-mode(3) ;
         }
         void rect(row1,col1,row2,col2,color)
         int col1,row1,col2,row2 ;
         char color ;
         { /* Эта функция генерирует заполненный прямоугольник */
           /* Предполагается, что row1 < row2 и col1 < col2 */
         unsigned char far *rgen = (char far *)(0xA0000000L) ;
         int rows = row2 - row1 ;  /* число строк */
         int cols = (col2 >> 3) - (col1 >> 3) - 1; /* всего столбцов */
         char left = (char)(0xFF >> (col1 & 7)) ;  /* левая маска */
         char rght = (char)~(0xFF >> (col2 & 7)) ; /* правая маска */
         char next_row ;
         char byte_per_line = (char)GET_CRT_COLS() ;
         register x,y ;
         char latch ;

         if (cols < 0)   /* Находятся ли col1 и col2 в одном байте? */
             left @= rght, cols = 0, rght = 0 ;
         rgen += bytes_per_line*row1 +(col1 >> 3) ;
         next_row = bytes_per_line - cols - 2 ;

         EGA_GRFX(5,2);               /* установить режим записи 2 */
         for(y = 0 ; y < rows ; y++)  /* выполнить каждую строку */

                                      - 9-22 -
         {
           EGA_BIT_MASK(left) ; /* установить левую маску бита */
           latch = *(rgen) ;    /* защелкнуть битовые матрицы EGA */
           *(rgen++) = color ;  /* установить цвет, указать для
                                   следующего байта */
           EGA_BIT_MASK(0xFF) ; /* отменить маску центра */
           for(x = 0; x < cols; x++)  /* выполнить каждый столбец */
              {
                 latch = *(rgen) ;
                 *(rgen++) = color ;
              }
           EGA_BIT_MASK(rght) ; /* установить правую маску бита */
           latch = *(rgen) ;    /* защелкнуть битовые матрицы EGA */
           *(rgen++) = color ;  /* установить цвет */
           rgen += next_row ;   /* перейти к следующей строке */
         }
         EGA_BIT_MASK(0xFF) ;   /* отменить маску бита */
         EGA_GRFX(5,0) ;        /* сбросить режим записи */
         }
         ----------------------------------------------------------------

             В программе  9-5 режим записи 2 устанавливается макрокомандой
         EGA_GRFX(5,2).  Вы должны быть внимательными и не посылать значе-
         ния, отличные от 0, 1, или 2 для EGA (0, 1, 2 или 3 для VGA), так
         как другие биты байта, направляемые регистру режима, имеют значе-
         ние для EGA. Регистры маски матрицы и маски бита эффективны в ре-
         жиме записи 2, а регистр установки/сброса бесполезен. Режим запи-
         си 0,  режим записи BIOS по умолчанию,  устанавливается с помощью
         EGA_GRFX(5,0).  Перед использованием  других программ или вызовов
         BIOS режим записи должен быть сброшен в 0.
             Режим записи 1 применяется для быстрого копирования одной об-
         ласти памяти EGA в другую. Это очень полезно для прокрутки, муль-
         типликации, а также сохранения и восстановления областей на экра-
         не.  Режим  записи 1 позволяет Вам копировать 4 байта в каждой из
         четырех битовых матриц за один цикл чтения или записи центрально-
         го процессора и во много раз быстрее чтения 4 отдельных байтов из
         битовых матриц с последующей записью 4 байтов по новому адресу.
             Для копирования  8 элементов смещение изображения памяти EGA,
         содержащее 8 элементов изображения,  считывается  для  подготовки
         регистров-защелок; затем смещение, содержащее назначение, записы-
         вается центральным процессором. Когда центральный процессор запи-
         сывает байт,  а режим записи установлен в 1,  EGA сбрасывает байт
         центрального процессора и копирует содержание регистров-защелок в
         каждую битовую матрицу.  Регистр маски бита не используется с ре-
         жимом записи 1. Все четыре байта в регистрах-защелках записывают-
         ся  во  все  четыре битовые матрицы независимо от установки маски
         бита. Регистр маски матрицы может быть использован для защиты от-
         дельных битовых матриц.
             Программа, представленная в листинге 9-6, демонстрирует режим
         записи 1.  Серия линий чертится в верхней части экрана. Затем эта
         серия копируется с использованием режима записи 1.  Наконец, гра-
         ница  образца быстро перечерчивается для демонстрации возможности
         мультипликации.



                                      - 9-23 -
                          Листинг 9-6. Программа MODEL.C
         ---------------------------------------------------------------
         /* mode1.c */
         /* Эта программа демонстрирует режим записи 1 EGA */
         #include <conio.h>
         #include <dos.h>
         #include <stdio.h>
         #include "ega.h"
         void copy( int,int,int,int,int );
         void main()
         {
            registr i,j;
            int k = 0;
            set_crt_mode(16) ; /*только усовершенствованный монитор!*/
            /* Рисует интересующую серию: */
            for(k = 0; k <= 4; ++k)
            for(j = 0+k; j <= 500+k; j += 5)
            for(i = 0+k; i <= 100+k; ++i)
               fastdot(i,i+j,13) ;
            for(k = 0; k <= 3; ++k)
            for(j = 0+k; j <= 500+k; j += 5)
            for(i = 0+k; i <= 100+k; ++i)
               fastdot(i,i+j,3) ;
            /* Скопировать серию на 120 строк вниз: */
            copy(0,0,105,639,   120,0) ;
            while(!kbhit())
            {
         /* Скопировать границу повторно,
         ** создает иллюзию движения: */
                copy(99,100,106,592,   219,100) ;
                copy(99,100,106,592,   219,108) ;
            }
            set_crt_modes(3) ;
         }

         void copy(r1_1, c1_1, r2_1, c2_1, r1_2, c1_2)
         int  r1_1, c1_1,   /* верхний левый угол источника */
              r2_1, c2_1,   /* нижний правый угол источника */
              r1_2, c1_2 ;  /* верхний левый угол назначения */
         {
         /* Быстро копирует одну область экрана в другую.
         ** Использует режим записи 1. Надо задать только
         ** верхний угол назначения.
         */
            char far *source = (char far *)(0xA0000000L) ;
            char far *destination = (char far *)(0xA0000000) ;
            int rows = r2_1 - r1_1 ;
            int cols = (c2_1 >> 3) - (c1_1 >> 3) ;
            int bytes_per_line = GET_CRT_COLS() ;
            int next_row = bytes_per_line - cols ;
            registr x,y ;
            source += bytes_per_line * r1_1 + (c1_1 >> 3) ;
            destination += bytes_per_line * r1_2 + (c1_2 >> 3) ;

            EGA_GRFX(5,1) ;     /* установить режим записи 1 */
            for(y = 0 ; y < rows ; y++)
            {

                                      - 9-24 -
               for(x = 0; x < cols; x++)
                 *(destination++) = *(source++) ;
               source += next_row ;
               destination += next_row ;
            }
            EGA_GRFX(5,0) ;   /* сбросить режим записи */
         }
         ----------------------------------------------------------------

             Поскольку регистр  маски бита не пригоден для использования в
         режиме записи 1, подпрограмма copy() будет копировать восемь эле-
         ментов  изображения  исходных байтов в байты назначения.  Другими
         словами,  режим записи 1 применяется для манипулирования байтами,
         а  не  элементами изображения.  Режим записи 1 можно использовать
         для сохранения области экрана на невидимой странице.  Это полезно
         для  реализации спускающихся меню.  Область под спускающимся меню
         может быть сохранена на невидимой странице и  затем восстановлена
         после использования меню. Режим записи 1 способен копировать дан-
         ные только в другую область памяти EGA. Для чтения цвета из памя-
         ти EGA требуется отдельное чтение четырех битовых матриц.
             VGA имеет один новый режим записи.  Режим записи 3 VGA сходен
         с использованием пары регистров установки/сброса и разрешения ус-
         тановки/сброса в режиме записи 0 EGA для установки цвета  (приме-
         няется подпрограммой line() программы 9-4). Разница заключается в
         том, что в режиме записи 3 регистр разрешения установки/сброса не
         используется,  поэтому значение, содержащееся в регистре установ-
         ки/сброса не маскируется регистром разрешения установки/сброса.


                               Чтение битовых матриц

             Поскольку каждый  байт  адресного  пространства  центрального
         процессора, зарезервированного для EGA, представляет 4 байта гра-
         фической  памяти,  память  EGA не может быть прочитана непосредс-
         твенно центральным процессором.  EGA возвратит  байт  из  битовой
         матрицы, выбранной в регистре выбора чтения битовой матрицы. Счи-
         тываемую матрицу необходимо  установить  перед  чтением  смещения
         EGA, содержащего интересующие Вас элементы изображения.
             Для определения цвета заданного элемента изображения требует-
         ся отдельное чтение из каждой битовой матрицы. Каждый бит 4-бито-
         вого значения цвета расположен в одной из четырех битовых матриц.
         Самый  значимый бит значения цвета находится в битовой матрице 3,
         а менее значимый бит в битовой матрице 0.  Регистр выбора  чтения
         матрицы  имеет  индекс  4 в графических чипах 1 и 2 EGA.  Так как
         каждая битовая матрица EGA должна считываться  отдельно, значение
         регистра выбора чтения матрицы соответствует только одной битовой
         матрице EGA в один момент времени.
             Функция в  программе 9-7 возвращает цвет элемента изображения
         на дисплее.  Так же как и fastdot(),  она читает цвет точки в не-
         сколько раз быстрее, чем эквивалентная подпрограмма BIOS.
             Смещение байта, содержащего элемент изображения, определяется
         точно также,  как и в подпрограмме fastdot(). Значение маски бита
         вычисляется определением номера бита изменяемого байта. Но значе-
         ние  маски  бита не посылается в регистр маски бита EGA.  Регистр
         маски бита EGA не влияет на байты,  читаемые EGA.  Маска бита ис-
         пользуется для изоляции элемента изображения от байта,  считывае-
         мого из битовой матрицы EGA.  Биты затем прибавляются матрица  за

                                      - 9-25 -
         матрицей к коду цвета элемента изображения. Регистр выбора чтения
         матрицы выбирает матрицу для чтения.  Битовые матрицы читаются  в
         обратном  порядке (матрица 3,  2,  1,  0),  так как это облегчает
         трансляцию кода.  Обратите внимание,  что регистр  выбора  чтения
         матрицы не сбрасывается в конце подпрограммы. При выполнении цик-
         ла в последний раз регистр выбора чтения  матрицы устанавливается
         в 0, значение по умолчанию.

          Листинг 9-7. Программа, возвращающая цвет элемента изображения
         -----------------------------------------------------------------

         /* возвращает цвет элемента изображения */
         int readdot(row,col)
         int row,col;
         {
            registr color = 0 ;
            registr latch ;
            unsigned char far *rgen = (char far *)(0xA0000000L +
                                      (col >> 3) +
                                      (row * GET_CRT_COLS())) ;
            int bit_number = (col & 7)^7 ;
            int bit_mask = (1 << bit_number) ;
            int plane ;
            /* Пройти через каждый массив 3, 2, 1, 0 */
            for(plane = 3; plane >= 0; plane--)
            {
               EGA_GRFX(4,plane) ;           /* выбрать массив */
               latch = *(rgen) & bit_mask ;  /* бит из этого массива */
               latch >>= bit_number ;        /* выровнять справа */
               color <<= 1 ;            /* место для следующего бита */
               color |= latch ;         /* прибавить бит */
            }
            return(color) ;
         }
         ----------------------------------------------------------------

                               Цветовые палитры EGA

             При использовании  с усовершенствованным цветным дисплеем EGA
         может отображать любые  16  цветов  из  64-цветной  палитры.  Для
         представления  16  цветов требуется 4 бита.  Каждый из этих битов
         соответствует одной из четырех битовых матриц EGA.  В режиме  CGA
         или в исходной палитре EGA 4 бита соответствуют красному, зелено-
         му, синему  ярким   цветам,  что обычно описывается IRGB.  Но как
         только исходная палитра EGA изменится, то 4-битовый код цвета бу-
         дет представлять собой просто индекс новой палитры.
             64-цветная палитра имеет те же три  основных  цвета  (красный,
         зеленый,   синий),  что  и  16-цветная  палитра,  но  бит  яркости
         отсутствует.  Вместо него каждый цвет имеет 2 бита для яркости от-
         дельного цвета,  что дает три уровня яркости каждого цвета.  Таким
         образом 64-цветная палитра может быть  представлена  6  битами  (3
         цвета  х  2 бита/цвет).  Биты меньшей яркости трех цветов являются
         самыми значимыми битами в 6-битовом значении  и  аббревиатура  rgb
         соответствует  красному,  зеленому  и синему цветам малой яркости.
         Самые незначимые 3 бита представляют красный, зеленый и синий цве-
         та  высокой  яркости  и  им соответствует аббревиатура RGB.  Общее
         6-битовое значение,  rgbRGB   используется для выбора одного из 64

                                      - 9-26 -
         цветов. Как только один из 16  отображаемых  цветов  установлен  в
         значение rgbRGB,  этот цвет может быть выбран с помощью 4-битового
         значения  IRGB.  Биты  значения  rgbRGB  будут  всегда  показывать
         красный,  зеленый и синий компоненты результирующего цвета,  но  с
         подключенным усовершенствованным цветным дисплеем,  значение  IRGB
         является просто индексом текущей палитры.
             Цвета rgbRGB могут применяться только с  EGA,  подключенным  к
         расширенному  цветному  монитору.  Когда  EGA подключен к цветному
         дисплею, могут использоваться только 16 цветов исходной палитры. В
         текстовых режимах и графических режимах EGA отдельные регистры па-
         литры могут быть установлены в любой из 16 исходных цветов.  В ре-
         жимах,  совместимых с CGA, палитра должна изменяться с использова-
         нием CGA-совместимых вызовов BIOS.
             EGA также  имеет  регистр  выходящей  строки развертки.  Цвет,
         посылаемый в этот регистр, отображается как граница. Тем не менее,
         выходящая  строка развертки приемлема только в режимах с 200 стро-
         ками развертки.
             Регистры палитры  EGA чаще всего устанавливаются с помощью но-
         вых вызовов EGA BIOS.  Вызов BIOS может установить или один из  16
         цветов, или все 16 цветов сразу. Вызов BIOS является функцией 0х10
         прерывания 0х10.  Имеется четыре подфункции:  0 устанавливает  от-
         дельные регистры палитры в любое значение rgbRGB (или в любое зна-
         чение IRGB,  если EGA не подключен к усовершенствованному цветному
         дисплею),  1  устанавливает регистр выходящей строки развертки,  2
         устанавливает все регистры палитры и регистр выходящей строки раз-
         вертки,  и  4  служит  переключателем между мерцанием текста и яр-
         костью. Подфункция выбирается в регистре AL.

                                Установить палитру

             Результат:  Int   0x10
             Вызывается: AH =  0х10
                         AL =  0, Установить отдельный регистр палитры
                         BL =  Изменяемый номер цвета (IRGB)
                         BH =  Установить значение rgbRGB
                         AL =  1, Установить регистр выходящей строки
                               развертки
                         BH =  Номер устанавливаемого цвета
                         AL =  2, Установить все регистры палитры и ре-
                               гистр выходящей строки развертки
                               ES:DX указывает на 17-байтовую таблицу
                               Байты 0 - 15 имеют 16 значений rgbRGB для
                               цветов 0 - 15
                               Байт 16 является номером цвета для ре-
                               гистра выходящей строки развертки
                         AL =  3, Переключает бит яркость/мерцание
                               Меняет значение бита 7 байта атрибута
                               текста
                         BL =  0, Разрешает яркость фона
                         BL =  1, Разрешает мерцание переднего плана
             К сожалению,  регистры палитры  EGA  только  записываемые.  В
         обычном  состоянии  невозможно определить,  какое значение rgbRGB
         представляет заданный номер цвета. При изменении регистров палит-
         ры EGA BIOS проверит наличие 256-байтовой таблицы, называемой об-
         ластью сохранения параметров.  Если эта таблица имеется,  то BIOS
         сохранит в ней значения rgbRGB. Здесь не рассматривается создание
         и сопровождение области сохранения параметров, но важно использо-

                                      - 9-27 -
         вать  вызовы BIOS для установки палитры таким образом,  чтобы эта
         таблица параметров обновлялась.
             VGA имеет  считываемые/записываемые регистры палитры, поэтому
         отдельные цвета rgbRGB могут быть определены чтением соответству-
         ющего регистра палитры.  VGA также имеет более широкую палитру, в
         которой любой из 16 отображаемых цветов может быть цветом из  па-
         литры 262.144  возможных цветов. Вместо 2 битов на цвет в EGA, VGA
         использует 6 битов на цвет (2 х 3 цвета = 262.144 цвета).
             Программа, представленная  в листинге 9-8,  демонстрирует ис-
         пользование регистров палитры.  Эта программа работает  только  в
         сочетании  EGA  с усовершенствованным цветным дисплеем (или VGA).
         Сначала программа,  применяя функцию rect() программы 9-5, начер-
         тит  16  цветных прямоугольников.  Затем палитра будет непрерывно
         меняться.

                         Листинг 9-8. Программа PALETTE.C
         ---------------------------------------------------------------

         /* palette.c */
         /* Демонстрирует палитру 64 цветов */
         #include <conio.h>
         #include <dos.h>
         #include <stdio.h>
         #include "ega.h"

         void set_all_pal(char*) ;
         void gotoXY(int,int) ;
         main()
         {
         int i,j,ch = 0;
         char palette[17] ;  /* эта матрица содержит палитру */
         set_crt_mode(16) ;  /* имейте правильный монитор! */

         /* Начертить несколько цветных штрихов: */
         printf("\nЦвет #:\n") ;
         for (i=0,j=0;i<16;++i,j+=40)
         {
            printf (" %2i ",i);
            rect(50,j,300,j+39,i);    /* из программы 9-5 */
            palette[i] = (char)i ;    /* инициализировать матрицу */
         }
            gotoXY(15,22) ;
            printf("rgbRGB цвета 7") ;
            printf("%c%c%c%c%c%c",205,205,205,205,205,190) ;
            gotoXY(20,0) ;
            printf("Нажмите Space для одного пробела, Esc для выхода");

            palette[16] = (char)0 ;
            while(ch != 27)          /* пока не нажата клавиша Esc */
               {
               if (kbhit())          /* если клавиша нажата, */
                 ch = getch() ;      /* принять символ */
               for (i = 1; i<=15; ++i)
                 {
                    palette[i]++;
                    if (palette[i] == 64)
                    /* максимальное значение rgbRGB */

                                      - 9-28 -
                        palette[i] = 1 ;
                 }
                 set_all_pal(palette) ;   /* установить палитру */
                 gotoXY(15,23) ;
                 /* Перевести значение rgbRGB в двоичное */
                 for(i = 5;i>=0; --i)
                 if(palette[7] & 1<<i)
                    putchar('1') ;
                 else
                    putchar('0') ;
                 if(ch == 32)         /* режим одного пробела */
                    while(!kbhit());
               }

         set_crt_mode(3) ;
         }

         /*==========================================================*/
         void set_all_pal(palette)
         char *palette ;
         /* Эта функция устанавливает всю палитру */
         {
         union REGS regs ;       /* регистры 8086 */
         struct SREGS segregs ;
         char far *fr = (char far *)palette ;
         regs.h.ah = 0x10 ;
         regs.h.al = 2 ;           /* функция для установки всего */
         segregs.es = FP_SEG(fp);  /* ES в сегмент палитры */
         regs.x.dx = FP_OFF(fp) ;  /* DX в смещение палитры */
         int86x(0x10, &regs, &regs, &segregs) ;
         }

         /*==========================================================*/
         void gotoXY(x,y)
         int x,y ;
         /* Эта функция перемещает курсор текста в x,y */
         {
            union REGS regs ;
            regs.h.ah = 2 ;            /* установить функцию курсора */
            regs.h.bh = 0 ;               /* страница 0 */
            regs.h.dh = (char)y ;         /* строка */
            regs.h.dl = (char)x ;         /* столбец */
            int86(0x10, &regs, &regs) ;   /* вызов прерывания 0х10 */
         }
         ----------------------------------------------------------------

                        Регистр циклического сдвига данных

             Регистр циклического сдвига данных позволяет Вам выбрать спо-
         соб комбинирования данных,  направляемых центральным процессором,
         в регистрах-защелках EGA.  Дополнительные параметры, имеющие дан-
         ные,  будут  логически  умножены,  сложены, сложены по модулю или
         оставлены неизменными с байтом в регистрах-защелках. Несмотря  на
         то,  что  регистр циклического сдвига данных может сдвигать байт,
         направляемый центральным процессором, на практике этому придается
         мало  значения.  Центральный процессор быстрее осуществляет сдвиг
         байта и требует менее продолжительную  установку.  Значащие  биты

                                      - 9-29 -
         регистра  циклического  сдвига данных показаны на рисунке 9-3,  а
         пример использования этого регистра приведен в программе 9-9.

            ┌─┬─┬─┬─┬─┬─┬─┬─┐
            │7│6│5│4│3│2│1│0│
            └─┴─┴─┴─┴─┴─┴─┴─┘
             └─┬─┘ └┬┘ └─┬─┘
               │    │    └───────── Счетчик циклического сдвига байта CPU
               │    │
               │    └────────────── Выбор функции
               │                       БИТЫ
               │                       4  3
               │                       0  0  Данные не изменяются
               │                       0  1  CPU байтANDбайты защелки
               │                       1  0  CPU байтORбайты защелки
               │                       1  1  CPU байтXORбайты защелки
               └─────────────────── Не используется на EGA

                   Рис.9-3. Регистр циклического сдвига данных



              Листинг 9-9. Пример использования регистра циклического
                                   сдвига данных
         ---------------------------------------------------------------

         main()
         {
            int i,j,k ;
            for(k=1;k<16;k++)
               {
               set_crt_mode(16) ;
               rect(0,0,200,639,k) ;    /* фон */
               EGA_GRFX(3,0) ;          /* сбросить регистр */
               for(i=0;i<13;i++)
               printf("\n") ;
               printf("   Не изменено    логически умножено") ;
               printf("   \t логически сложено    сложено по модулю") ;
               for(i=0, j=0, i<4; j=160*(i+1),i++)
               {
                   switch(i)
                   {
                     case 1:EGA_GRFX(3,8) ;
                     /* логически умножить содержание регистра */
                     case 2:EGA_GRFX(3,16) ;
                     /* логически сложить содержание регистра */
                     case 3:EGA_GRFX(3,24) ;
                     /* сложить по модулю содержание регистра */
                   }
                     /* Сейчас начертить прямоугольники: */
                     rect(20,20+j,100,99+j,1) ;
                     rect(40,40+j,120,119+j,1<<1) ;
                     rect(60,60+j,140,139+j,1<<2) ;
                     rect(80,80+j,160,159+j,1<<3) ;
                   }
               gerch() ;
               }

                                      - 9-30 -
         set_crt_mode(3) ;
         }
         ---------------------------------------------------------------

                         Режим отображения 256 цветов VGA

             VGA имеет новый видеорежим,  режим 19,  который может отобра-
         жать 256 цветов из палитры 262.144 цветов. Концептуально режим 19
         достаточно прост.  Так как каждый элемент изображения представля-
         ется одним байтом дисплейной памяти, упрощены вычисления, опреде-
         ляющие смещение каждого элемента изображения.   Программа,  пред-
         ставленная в  листинге  9-10,  служит  примером  режима  19  VGA.
         Отображаются все 256 цветов. Первые 16 цветов такие же, как цвета
         палитр CGA,  VGA и EGA.  Следующие  21  цвет  принадлежат  серому
         спектру.  Заключительные 216 цветов представляют собой три группы
         по 72 цвета.  В каждой группе цвета плавно переходят от синего  к
         красному и зеленому. Три группы соответствуют уменьшению насыщен-
         ности или увеличению белизны.

                        Листинг 9-10. Пример режима 19 VGA.
         ---------------------------------------------------------------

         void fast(int, int, int) ;

         main()
         {
           registr i, j ;
           struct Ega_info info ;
           if(get_ega_info(&info))
              if(info.card == 'V')       /* карта VGA? */
                 set_crt_mode(19) ;
              else
                 return ;
           else
              return ;

           for(i=0x0; i<=0xFF; i++)      /* вывести палитру */
              for(j=0; j<200; j++)
              fast19(j,i,i) ;
         }
         void fast19(row,col,color)
         int row, col, color ;
         {
            /* так как каждый байт является элементом изображения,
            ** смещение элемента изображения это
            ** (строка * 320 байтов/строка) + столбец
            ** также отсутствует маска бита */
            unsigned char far *rgen = (char far *)(0xA0000000L +
                                      (row * 320) + col) ;
            *rgen = (unsigned char)color ;
         }
         --------------------------------------------------------------

             В программу 9-10 включена подпрограмма непосредственной запи-
         си точки в видеопамять, fast19(), для режима отображения 256 цве-
         тов VGA.  Поскольку каждый элемент изображения использует 1  байт
         дисплейной  памяти,  подпрограмма  может быть очень направленной.

                                      - 9-31 -
         Нет необходимости в длинных вычислениях памяти или  манипуляции с
         маской бита или маской матрицы. Похоже, что подпрограмма, возвра-
         щающая значение элемента изображения,  ведет прямо вперед. Просто
         замените оператор *rgen = color ; оператором return(*rgen) ;.


                                    Заключение

             С использованием EGA все запутано.  Фирма  IBM  разрабатывала
         EGA  для  поддержки двух совершенно разных стандартов отображения
         (CGA и MDA). Результат в настоящее время поддерживается еще более
         сложным режимом VGA.  Лучшим способом создания программного обес-
         печения,  работающего с EGA или VGA и  не  жертвующего  совмести-
         мостью,  является разделение аппаратно-зависимого кода в логичес-
         ки-независимые функции. Например, подпрограмму fastdot() програм-
         мы 9-5 легко переписать для нового режима отображения  256 цветов
         VGA.   Более   сложную   подпрограмму  вывода,  которая  вызывает
         fastdot() для вычерчивания точек,  не надо переписывать,  так как
         fastdot() поддерживает новый режим.
             В этой главе рассмотрено несколько основных графических функ-
         ций:  line(), fastdot(), readdot() и rect(). Обсуждены такие осо-
         бенности  EGA,  как регистры-защелки.  Также показаны три способа
         установки цвета EGA - регистр маски  матрицы,  регистр   установ-
         ки/сбора и режим записи 2.  Несмотря  на то,   что указанные под-
         программы работают быстро, их можно усовершенствовать. Высокопро-
         изводительные графические подпрограммы, использующие EGA или VGA,
         будут найдены в процессе исследования.
