Мы начнем рассмотрение нестандартных режимов с режима, имеющего разрешение 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"); }