На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 9 / Много точек Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Много точек

Для достижения максимальной производительности уникальных аппаратных средств 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 
         #include 
         #include 
         #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) ;
             getch() ;  /* ждать нажатия клавиши */
           set_crt_mode(info.text_mode);
           }
           else
           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 х 8 элементов/байт. Высота должна быть точно определена из таблицы, содержащей количество вертикальных линий развертки для каждого режима. Однако, это более быстрый, но менее точный способ. И число строк символов, и размер точки (байта на символ) можно запрограммировать, кроме того, любой из них можно изменить. Но высота прямоугольника для символа в байтах и число строк развертки определяют количество строк. Так как слово с адресом 0х40:0х85 содержит байты на символ и байт с адресом 0:40х0:84 содержит количество строк, они могут быть использованы для вычисления числа строк развертки для любого видеорежима. Оператор языка Си вычисляет приблизительное значение общего числа линий развертки. Значение вычисляется приблизительно, так как число строк изменяется и не всегда на 1. Как только станут известны данные EGA, программа чертит серию линий, которые не зависят от используемого графического режима EGA.


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

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz