Мы начнем рассмотрение нестандартных режимов с режима, имеющего разрешение 320х400 пикселов. Программирование этого режима является самым простым и безопасным, так как при его установке нам не придется изменять содержимое регистров контроллера ЭЛТ.
Как мы указывали при описании режимов видеоадаптеров, в режиме 13h используется двойное сканирование. То есть в этом режиме - 320х200 пикселов на самом деле отображается не 200, а 400 линий сканирования. Перепрограммировав несколько регистров адаптера можно перевести его в режим 320х400 пикселов.
Рассмотрим последовательность действий, необходимую для перевода видеоадаптера в нестандартный режим с разрешением 320х400 пикселов:
Теперь мы приведем программу, которая реализует изложенный алгоритм и переводит видеоадаптер в режим отображающий 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"); }