Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Программирование видеоадаптеров CGA, EGA и VGA

© Александр Фролов, Григорий Фролов
Том 3, М.: Диалог-МИФИ, 1992, 287 стр.

[Назад] [Содеожание] [Дальше]

7.8. Нестандартные режимы видеоадаптера VGA

В этой главе на примере видеоадаптера VGA мы рассмотрим программирование нестандартных режимов. Так как программирование нестандартных режимов видеоадаптеров требует непосредственного доступа к его регистрам, то перед чтением этой главы вам необходимо подробно изучить назначение регистров адаптера.

Мы рассмотрим два наиболее интересных с нашей точки зрения нестандартных режимов VGA: 320х400 и 360х480 пикселов при 256 цветах.

Эти режимы нельзя установить на обычных VGA адаптерах с помощью функций BIOS. С помощью BIOS можно установить только один режим с 256-цветной палитрой - 13h (320х200 пикселов, 256 цветов). Однако если вы воспользуетесь возможностью непосредственного программирования адаптера через регистры, то любой адаптер VGA можно перевести в эти режимы.

Программирование всех трех описанных ниже нестандартных режимов мы проведем в два этапа:

  • устанавливаем при помощи BIOS стандартный режим 13h (320х200 пикселов, 256 цветов),
  • изменяем содержимое некоторых регистров видеоадаптера, отвечающих за структуру видеопамяти и разрешающую способность.

Такой подход к установке нестандартных режимов позволяет нам программировать не все регистры адаптера, а только те, которые нуждаются в изменении.

Организация видеопамяти

Режим 13h использует простую линейную организацию видеопамяти, в которой по каждому адресу в видеопамяти находится один байт управляющий одним пикселом. Такая организация видеопамяти хотя и облегчает программирование, но не позволяет увеличить разрешающую способность. Дело в том, что в режиме 13h адресное пространство видеопамяти ограничено 64K, которых хватает как раз для того, чтобы получить разрешающую способность 200х320 точек при 256 цветах (200*320 = 64000). Кроме того такая организация видеопамяти не позволяет использовать для копирования видеоданных регистры-защелки, что может существенно повысить скорость работы программ.

Исходя из вышесказонного для нашего нестандартного режима используется другая структура видеопамяти, более схожая со структурой видеопамяти режимов 10h и 12h. На следующем рисунке представлена структура видеопамяти используемая нами во всех описываемых нестандартных режимах:

Рисунок 8.18 Структура видеопамяти в нестандартных, 256-цветовых режимах.

Как видно из рисунка первый пиксел экрана, отображаемый в левом верхнем углу, определяется байт со смещением 0 из нулевого цветового слоя. Второй пиксел определяется байтом со смещением 0 из первого слоя, третий пиксел - байтом со смещением 0 из второго слоя, четвертый пиксел - байтом со смещением 0 из третьего слоя. Пятый пиксел определяется байтом со смещением 1 из нулевого слоя и так далее.

Таким образом для пиксела с координатами x и y байт, который определяет его цвет, расположен со смещением (x + y * PIXEL_PER_LINE) / 4, в цветовой плоскости (x + y * PIXEL_PER_LINE) mod 4. В этой формуле константа PIXEL_PER_LINE должна определять горизонтальную разрешающую способность экрана в данном режиме.

Такая организация видеопамяти, хотя и более неудобна для вычисления адреса пикселов, чем линейная организация памяти режима 13h, но дает другие неоспаримые преимущества.

Во первых, в режиме с разрешением 320х400 пикселов мы можем использовать две страницы видеопамяти, первая из них имеет нулевое смещение, а вторая смещение 8000h от начала видеопамяти. Режим с разрешением 360х480 пикселов позволяет иметь только одну страницу, но так как он использует только 172800 байт из 256 килобайт, то неиспользуемую память можно использовать для хранения пиктограмм и шрифтов.

Во вторых, организация видеопамяти в виде отдельных цветовых слоев позволяет использовать для операций копирования и заполнения областей видеопамяти регистры-защелки. Это дает возможность одновременно копировать четыре байта, и следовательно значительно увеличить скорость работы программ.

Режим 320х400 пикселов, 256 цветов

Мы начнем рассмотрение нестандартных режимов с режима, имеющего разрешение 320х400 пикселов. Программирование этого режима является самым простым и безопасным, так как при его установке нам не придется изменять содержимое регистров контроллера ЭЛТ.

Как мы указывали при описании режимов видеоадаптеров, в режиме 13h используется двойное сканирование. То есть в этом режиме - 320х200 пикселов на самом деле отображается не 200, а 400 линий сканирования. Перепрограммировав несколько регистров адаптера можно перевести его в режим 320х400 пикселов.

Рассмотрим последовательность действий, необходимую для перевода видеоадаптера в нестандартный режим с разрешением 320х400 пикселов:

  • Устанавливаем при помощи BIOS стандартный режим 13h (320х200 пикселов, 256 цветов), при этом программируются все регистры видеоадаптера. Затем мы изменим содержимое только нескольких регистров. Такой подход значительно облегчит нам задачу, так как уменьшится количество регистров, которые необходимо изменить.
  • Изменяем структуру видеопамяти, чтобы иметь воможность адресоваться к 256 килобайтам. Для этого в регистре определения структуры памяти синхронизатора запрещаем режимы в которых доступ по разным адресам (кратным двум и/или кратным четырем) осуществляется к различным цветовым слоям памяти. А в регистре режима работы графического контроллера сбрасываем в ноль бит управления четным/нечетным режимом. Это запрещает доступ по четным адресам к четным цветовым слоям, а по нечетным адресам - к нечетным цветовым слоям видеопамяти. Затем в регистре смешанного назначения графического контроллера сбрасываем бит управляющий сцеплением четных и нечетных слоев памяти. После этих действий видеопамять по своей структуре напоминает режим 10h, за исключением того, что каждый пиксел управляется одним байтом, расположенном в одной из слоев видеопамяти.
  • Очищаем видеопамять (для одной или двух страниц по необходимости), так как при установке режима 13h BIOS очищает только первые 64K из 256K. Остальная видеопамять может содержать мусор который отобразится на экране после перепрограммирования контроллера ЭЛТ.
  • Выключаем режим двойного сканирования. Для этого сбрасываем в ноль бит управления двойным сканированием и устанавливаем высоту символов равную единице.
  • Переводим контроллер ЭЛТ в режим адресации видеопамяти по байтам. Для этого выключаем режим адресации по двойным словам в регистре положения подчеркивания символа и включаем режим адресации по байтам в регистре управления режимом работы. Теперь по каждому адресу расположено четыре байта в различных цветовых слоях видеопамяти.

Теперь мы приведем программу, которая реализует изложенный алгоритм и переводит видеоадаптер в режим отображающий 256 цветов при разрешающей способности 320х400 пикселов.

/**
*      Включаемый файл vga_new.h
**/

// сегмент видеопамяти для режима 13h
#define VGA_SEGMENT     0a000h     


// регистр определения различных режимов работы
#define MOR  3c2h    

// адрес индексного порта синхронизатора
#define SC_INDEX   3c4h  

   // регистр разрешения записи цветового слоя
   #define CPWER   2    

   // регистр определения структуры памяти
   #define MMR     4    


// адрес индексного порта графического контроллера
#define GC_INDEX   3ceh  

   // регистр выбора читаемого слоя
   #define RPSR    4   

   // регистр режима работы
   #define MDR     5   

   // регистр смешанного назначения
   #define MIR     6   


// адрес индексного порта контроллера ЭЛТ (цветной режим)   
#define CRTC_INDEX      3d4h     

   // регистр высоты символов текста
   #define MSLR    9    

   // регистр начального адреса
   #define SAR_h   0ch  

   // регистр положения подчеркивания символа
   #define ULR     14h  

   // регистр управления режимом
   #define MCR     17h  


// режим 320х400 пикселов

// число пикселов по вертикали 
#define SCREEN_HEIGHT  400 

// число пикселов по горизонтали  
#define SCREEN_WIDTH   320 


// режим 360х480 пикселов

// число пикселов по вертикали 
#define SCREEN_HEIGHT_H 480 

// число пикселов по горизонтали 
#define SCREEN_WIDTH_H  360 
/**
*      Файл   e256mres.c
**/
#include "sysp.h"
#include "sysgraph.h"
#include <dos.h>

#include    <graph.h>
#include    "vga_new.h"

/**
*.Name    Set320x400Mode
*
*.Title   Установка режима 320х400 пикселов, 256 цветов.
*
*.Proto   void Set320x400Mode( void )
*
*.Params  Не используются.
*
*.Return  Не используетя.
*
*.Sample  e256mres.c
**/

void    Set320x400Mode( void ) {

   _asm  {

      // сохраняем регистр di
      push    di

      // устанавливаем стандартный режим 13h (320x200
      // пикселов, 256 цветов)
      mov     ax,0013h
      int     10h

      // выбираем регистр определенияя структуры памяти
      mov     dx,SC_INDEX
      mov     al,MMR
      out     dx,al

      // считываем значение регистра определения
      // структуры памяти
      inc     dx
      in      al,dx

      // сбрасываем бит D4
      and     al,11110111b

      // устанавливаем бит D3, при этом выключается
      // режим адресации по четным и нечетным адресам к
      // разным слоям памяти
      or      al,00000100b

      // записываем в регистр новое значение
      out     dx,al


      // после загрузки в этот регистр нового значения
      // структура видеопамяти соответствует режимам 10h
      // и 12h за исключением того, что каждому пикселу
      // соответствует один байт видеопамяти

      // выбираем регистр режима работы графического
      // контроллера

      mov     dx,GC_INDEX
      mov     al,MDR
      out     dx,al

      // считываем его значение
      inc     dx
      in      al,dx
      
      // выключаем доступ по четным адресам к четным
      // слоям, а по нечетным адресам к нечетным слоям
      and     al,11101111
      out     dx,al

      // выбираем регистр смешанного назначения
      // графического контроллера
      dec     dx
      mov     al,MIR
      out     dx,al

      // считываем его значение
      inc     dx
      in      al,dx

      // сбрасываем бит управляющий сцеплением четных и
      // нечетных слоев
      and     al,11111101b
      out     dx,al

      // разрешаем запись днных во все четыре цветовых
      // слоя, записывая число 0fh в регистр разрешения
      // записи цветового слоя

      mov     dx,SC_INDEX
      mov     al,CPWER
      out     dx,al

      inc     dx
      mov     al,00001111b
      out     dx,al

      // очищаем первую страницу видеопамяти, так как
      // установка ржима 13h очищает только первые 64K

      mov     ax,VGA_SEGMENT
      mov     es,ax

      xor     di,di
      mov     ax,di

      mov     cx,8000h
      cld
      rep     stosb

      // выбираем регистр высоты символов текста
      // контроллера ЭЛТ
      mov     dx,CRTC_INDEX
      mov     al,MSLR
      out     dx,al

      inc     dx
      in      al,dx

      // запрещаем двойное сканирование
      and     al,01100000b
      out     dx,al

      // выбираем регистр положения подчеркивания
      // символа
      dec     dx
      mov     al,ULR
      out     dx,al

      // выключаем режим адресации видеопамяти по
      // двойным словам
      inc     dx
      in      al,dx
      and     al,10111111b
      out     dx,al

      // выбираем регистр управления режимом
      dec     dx
      mov     al,MCR
      out     dx,al

      // включаем байтовый режим адресации
      inc     dx
      in      al,dx
      or      al,01000000b
      out     dx,al

      pop     di
   }
}




/**
*.Name    WritePixel
*
*.Title   Отображение пиксела.
*
*.Descr   Функция отображает на экране пиксел в заданных
*      координатах,
*         определенного цвета.
*
*.Proto   void WritePixel(unsigned x, unsigned y, unsigned
*                char color)
*
*.Params  x - x-координата пиксела (0-319),
*
*         y - y-координата пиксела (0-399),
*
*         color - цвет пиксела (0-255).
*
*.Return  Не используетя.
*
*.Sample  e256mres.c
**/

void  WritePixel(unsigned x, unsigned y,
           unsigned char color) {

   _asm  {

      push    di

      mov     cx,x
      mov     dx,y
      mov     bl,color

      mov     ax,VGA_SEGMENT
      mov     es,ax

      mov     ax,( SCREEN_WIDTH / 4 )
      mul     dx

      push    cx

      shr     cx,1
      shr     cx,1

      add     ax,cx
      mov     di,ax

      pop     cx

      and     cl,3
      mov     ah,1
      shl     ah,cl

      mov     dx,SC_INDEX
      mov     al,CPWER
      out     dx,ax

      mov     es:[di],bl

      pop     di
   }
}



/**
*.Name    ReadPixel
*
*.Title   Определение цвета пиксела.
*
*.Descr   Функция возвращает значение байта видеопамяти,
*      определяющего пиксел 
*         с заданными координатами.
*
*.Proto   unsigned char ReadPixel(unsigned x, unsigned y,
*                       unsigned char color)
*
*.Params  x - x-координата пиксела (0-319),
*
*         y - y-координата пиксела (0-399).
*
*.Return  цвет пиксела (0-255).
*
*.Sample  e256mres.c
**/

unsigned char   ReadPixel( unsigned x, unsigned y ) {

   unsigned char  color;

   _asm  {

      push    si

      mov     cx,x
      mov     dx,y

      mov     ax,VGA_SEGMENT
      mov     es,ax

      mov     ax,( SCREEN_WIDTH / 4 )
      mul     dx

      push    cx

      shr     cx,1
      shr     cx,1

      add     ax,cx
      mov     si,ax

      pop     ax

      and     al,3
      mov     ah,al

      mov     dx,GC_INDEX
      mov     al,RPSR
      out     dx,ax

      mov     al,es:[si]
      mov     color,al

      pop     si
   }

   return( color );
}


/**
*.Name    Full_Scr
*
*.Title   Закрашивает экран заданным цветом.
*
*.Proto   void Full_Scr( unsigned char color )
*
*.Params  color - цвет экрана (0-255).
*
*.Return  Не используетя.
*
*.Sample  e256mres.c
**/

void Full_Scr( unsigned char color ) {

   _asm {

      ;разрешаем запись данных во все четыре цветовых
      ;слоя

      push    di

      mov     dx,SC_INDEX
      mov     al,CPWER
      out     dx,al

      inc     dx
      mov     al,0fh
      out     dx,al


      mov     ax,VGA_SEGMENT
      mov     es,ax

      xor     di,di
      mov     al,color

      mov     cx,32000
      cld
      rep     stosb

      pop     di
   }
}



// функция LoadVGA256 загружает регистры таблицы цветов
// цифро-аналогового преобразователя новыми значениями

void LoadVGA256(void) {

   RGB color_table[256];
   unsigned char   i, j;
   unsigned char   far *ptr;
   unsigned seg_table,off_table;

// записываем в массив color_table новые значения для
// регистров таблицы цветов

   for(j = 0; j < 4; j++) {
      for(i = 0; i < 64; i++) {
         (color_table[i+j*64]).red = (j == 0) ? i : 0;

         (color_table[i+j*64]).green = 
               (j == 1) ? i : (j == 3) ? i : 0;

         (color_table[i+j*64]).blue = 
               (j == 2) ? i : (j == 3) ? i : 0;
      }
   }

   ptr = (unsigned char far*) &color_table[0];

// определяем сегмент и смешение массива color_table

   seg_table = FP_SEG(ptr);
   off_table = FP_OFF(ptr);

// загружаем новые значения в регистры таблицы цветов

   SetVgaDAC(seg_table,off_table);

// функция SetVgaDAC загружает регистры таблицы цветов 
// цифро-аналогового преобразователя
// исходный текст функции приведен при описании регистра
// данных таблицы цветов ЦАП VGA (файл vga256.c)
}


//
//   главная функция
//
void main( void ){

   unsigned i;
   char ch = 13;

   struct videoconfig vc;

   // заполняем поля структуры vc

   printf("\n   (C) Frolov G.V., 1992 \n\n");
   _getvideoconfig( &vc );

   // завершаем программу если нет VGA адаптера

   if(vc.adapter != _VGA) {
      printf("Для выполнения программы необходим"
           " адаптер VGA.\n");

      exit(0);
   }

   // устанавливаем режим 320х400 пикселов, 256 цветов

   Set320x400Mode();

   // загружаем регистры ЦАП VGA

   LoadVGA256();


   for(i = 0; i < 400; i++)
      WritePixel(160, (unsigned) i,
                   (unsigned char) (i % 256) );

   for(i = 0; i < 320; i++)
      WritePixel((unsigned) i, 200,
                   (unsigned char) (i % 256) );

   ch = getch();
   if( ch == 27 ) exit(1);

   for(i = 0; i < 320; i++)
      WritePixel((unsigned) i, (unsigned) i,
                   (unsigned char) (i % 256) );

   ch = getch();

   for(i = 0; ((i < 256) && (ch != 27)); i++) {
      Full_Scr( (unsigned char) i );
      ch = getch();
   }


   // возвращаемся в текстовый режим

   _setvideomode(_DEFAULTMODE);

   printf("Привет всем!!!\n");
}

Режим 360х480 пикселов, 256 цветов

Второй рассматриваемый нами нестандартный режим может отображать 256 цветов при разрешающей способности 360х480 пикселов. Программирование этого режима является менее простыми безопасным, чем предыдущего режима, так как нам придется изменять содержимое регистров контроллера ЭЛТ, отвечающих за временные характеристики видеоадаптера. В остальном программирование видеоадаптера осуществляется по тем же правилам, что и в режиме с разрешающей способностью 320х400 пикселов.

Ниже приведена программа, которая переводит видеоадаптер в нестрандартный режим с разрешением 360х480 пикселов:

/**
*      Файл    e256hres.c
**/
#include "sysp.h"
#include "sysgraph.h"
#include <dos.h>

#include    <graph.h>
#include    "vga_new.h"

/**
*.Name    Set360x480Mode
*
*.Title   Установка режима 360х480 пикселов, 256 цветов.
*
*.Proto   void Set360x480Mode( void )
*
*.Params  Не используются.
*
*.Return  Не используетя.
*
*.Sample  e256hres.c
**/

void    Set360x480Mode( void ) {

   _asm  {

   // устанавливаем режим 12h, чтобы очистить видеопамять
      mov     ax,12h
      int     10h

   // устанавливаем стандартный режим 13h 
      mov     ax,0013h
      int     10h

   // перепрограммируем регистр определения структуры
   //  памяти: запрещаем адресацию к разным слоям памяти в
   // зависимости от кратности адреса памяти четырем (бит
   // D4 - chain4)
      mov   dx,SC_INDEX
      mov   ax,0604h
      out   dx,ax

   // производим синхронный сброс и остановку
   // синхронизатора
      mov   ax,0100h
      out   dx,ax

   // адресуемся к регистру определения различных режимов
   // работы
      mov   dx,MOR

   // устанавливаем частоту кадров 60Кц
      mov   al,0e7h
      out   dx,al

   // запускаем синхронизатор
      mov   dx,SC_INDEX
      mov   ax,0300h
      out   dx,ax


   // выбираем регистр режима работы графического
   // контроллера
      mov     dx,GC_INDEX
      mov     al,MDR
      out     dx,al

   // считываем его значение
      inc     dx
      in      al,dx

   // выключаем доступ по четным адресам к четным слоям, а
   // по нечетным адресам к нечетным слоям
      and     al,11101111
      out     dx,al

   // выбираем регистр смешанного назначения графического
   // контроллера
      dec     dx
      mov     al,MIR
      out     dx,al

   // считываем его значение
      inc     dx
      in      al,dx

   // сбрасываем бит управляющий сцеплением четных и
   // нечетных слоев
      and     al,11111101b
      out     dx,al


   // выбираем регистр конца обратного вертикального хода
   // луча
      mov   dx,3d4h
      mov   al,11h
      out   dx,al

   // снимаем защиту от записи с регистров контроллера
   // ЭЛТ, имеющих индексы от 0 до 7
      inc   dx
      in    al,dx
      and   al,7fh
      out   dx,al

      dec   dx

   // программируем регистры контроллера ЭЛТ, втом числе
   // регистры, определяющие временные параметры режима

   // устанавливаем регистр общей длины линии
   // горизонтальной развертки
      mov   ax,06b00h
      out   dx,ax

   // устанавливаем регистр длины отображаемой части
   // горизонтальной развертки
      mov   ax,05901h
      out   dx,ax

   // устанавливаем регистр начала импульса гашения луча
   // горизонтальной развертки
      mov   ax,05a02h
      out   dx,ax

   // устанавливаем регистр конца импульса гашения луча
   // горизонтальной развертки
      mov   ax,08e03h
      out   dx,ax

   // устанавливаем регистр начала импульса
   // горизонтального обратного хода луча
      mov   ax,05e04h
      out   dx,ax

   // устанавливаем регистр конца импульса горизонтального
   // обратного хода луча
      mov   ax,08a05h
      out   dx,ax

   // устанавливаем регистр числа горизонтальных линий
   // растра
      mov   ax,0d06h
      out   dx,ax

   // устанавливаем дополнительный регистр
      mov   ax,03e07h
      out   dx,ax

   // устанавливаем регистр высоты символов текста
      mov   ax,04009h
      out   dx,ax

   // устанавливаем регистр начала обратного
   // вертикального хода луча
      mov   ax,0ea10h
      out   dx,ax

   // устанавливаем регистр конца обратного
   // вертикального хода луча
      mov   ax,0ac11h
      out   dx,ax

   // устанавливаем регистр начала гашения вертикальной
   // развертки
      mov   ax,0df12h
      out   dx,ax

   // устанавливаем регистр логической ширины экрана
      mov   ax,02d13h
      out   dx,ax

   // устанавливаем регистр положения подчеркивания
   // символа
      mov   ax,014h
      out   dx,ax

   // устанавливаем регистр начала импульса гашения
   // вертикальной развертки
      mov   ax,0e715h
      out   dx,ax

   // устанавливаем регистр конца импульса гашения
   // вертикальной развертки
      mov   ax,0616h
      out   dx,ax

   // устанавливаем регистр управления режимом
      mov   ax,0e317h
      out   dx,ax
   }
}


/**
*.Name    WritePixel_H
*
*.Title   Отображение пиксела.
*
*.Descr   Функция отображает на экране пиксел в заданных
*       координатах, определенного цвета.
*
*.Proto   void WritePixel_H(unsigned x, unsigned y, unsigned
*                  char color)
*
*.Params  x - x-координата пиксела (0-319),
*
*         y - y-координата пиксела (0-399),
*
*         color - цвет пиксела (0-255).
*
*.Return  Не используетя.
*
*.Sample  e256hres.c
**/

void  WritePixel_H(unsigned x, unsigned y, 
                   unsigned char color) {

   _asm  {

      push    di

      mov     cx,x
      mov     dx,y
      mov     bl,color


      mov     ax,VGA_SEGMENT
      mov     es,ax

      mov     ax,( SCREEN_WIDTH_H / 4 )
      mul     dx

      push    cx

      shr     cx,1
      shr     cx,1

      add     ax,cx
      mov     di,ax

      pop     cx

      and     cl,3
      mov     ah,1
      shl     ah,cl

      mov     dx,SC_INDEX
      mov     al,CPWER
      out     dx,ax

      mov     es:[di],bl

      pop     di
   }
}


/**
*.Name    ReadPixel_H
*
*.Title   Определение цвета пиксела.
*
*.Descr   Функция возвращает значение байта видеопамяти,
*      определяющего пиксел с заданными координатами.
*
*.Proto   unsigned char ReadPixel_H(unsigned x, unsigned y,
                      unsigned char color)
*
*.Params  x - x-координата пиксела (0-319),
*
*         y - y-координата пиксела (0-399).
*
*.Return  цвет пиксела (0-255).
*
*.Sample  e256hres.c
**/

unsigned char   ReadPixel_H( unsigned x, unsigned y ) {

   unsigned char  color;

   _asm  {

      push    si

      mov     cx,x
      mov     dx,y

      mov     ax,VGA_SEGMENT
      mov     es,ax

      mov     ax,( SCREEN_WIDTH_H / 4 )
      mul     dx

      push    cx

      shr     cx,1
      shr     cx,1

      add     ax,cx
      mov     si,ax

      pop     ax

      and     al,3
      mov     ah,al

      mov     dx,GC_INDEX
      mov     al,RPSR
      out     dx,ax

      mov     al,es:[si]
      mov     color,al

      pop     si
   }

   return( color );
}


/**
*.Name    Full_Scr_H
*
*.Title   Закрашивает экран заданным цветом.
*
*.Proto   void Full_Scr_H( unsigned char color )
*
*.Params  color - цвет экрана (0-255).
*
*.Return  Не используетя.
*
*.Sample  e256hres.c
**/

void Full_Scr_H( unsigned char color ) {

   _asm {

      push    di

      ;разрешаем запись данных во все четыре цветовых слоя

      mov     dx,SC_INDEX
      mov     al,CPWER
      out     dx,al

      mov     al,0fh
      out     dx,al


      mov     ax,VGA_SEGMENT
      mov     es,ax

      xor     di,di
      mov     al,color

      mov     cx,43200
      cld
      rep     stosb

      pop     di
   }
}


// функция LoadVGA256 загружает регистры таблицы цветов
// цифро-аналогового преобразователя новыми значениями

void LoadVGA256(void) {

   RGB color_table[256];
   unsigned char   i, j;
   unsigned char   far *ptr;
   unsigned seg_table,off_table;

// записываем в массив color_table новые значения для
// регистров таблицы цветов

   for(j = 0; j < 4; j++) {
      for(i = 0; i < 64; i++) {
         (color_table[i+j*64]).red = (j == 0) ? i : 0;

         (color_table[i+j*64]).green = 
               (j == 1) ? i : (j == 3) ? i : 0;

         (color_table[i+j*64]).blue = 
               (j == 2) ? i : (j == 3) ? i : 0;
      }
   }

   ptr = (unsigned char far*) &color_table[0];

// определяем сегмент и смешение массива color_table

   seg_table = FP_SEG(ptr);
   off_table = FP_OFF(ptr);

// загружаем новые значения в регистры таблицы цветов

   SetVgaDAC(seg_table,off_table);

// функция SetVgaDAC загружает регистры таблицы цветов 
// цифро-аналогового преобразователя
// исходный текст функции приведен при описании регистра
// данных таблицы цветов ЦАП VGA (файл vga256.c)
}

//
//   главная функция
//
void main( void ){

   unsigned i;
   char ch = 13;

   struct videoconfig vc;

   // заполняем поля структуры vc

   printf("\n   (C) Frolov G.V., 1992\n\n");
   _getvideoconfig( &vc );

   // завершаем программу если нет VGA адаптера

   if(vc.adapter != _VGA) {
      printf("Для выполнения программы нобходим"
            " адаптер VGA\n");
      exit(0);
   }


   // устанавливаем режим 360х480 пикселов, 256 цветов

   Set360x480Mode();

   // загружаем регистры ЦАП VGA

   LoadVGA256();

   for(i = 0; i < 480; i++)
      WritePixel_H(180, (unsigned) i,
                  (unsigned char) (i % 256) );

   for(i = 0; i < 360; i++)
      WritePixel_H((unsigned) i, 240,
                  (unsigned char) (i % 256) );

   ch = getch();
   if( ch == 27 ) exit(1);

   for(i = 0; i < 360; i++)
      WritePixel_H((unsigned) i, (unsigned) i,
               (unsigned char) (i % 256) );

   ch = getch();

   for(i = 0; ((i < 256) && (ch != 27)); i++) {
      Full_Scr_H( (unsigned char) i );
      ch = getch();
   }


   // возвращаемся в текстовый режим

   _setvideomode(_DEFAULTMODE);

   printf("Привет всем!!!\n");
}




[Назад] [Содеожание] [Дальше]