#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,11101111b
		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,not 1fh

		// запрещаем двойное сканирование
		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
	}
}


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");
}
