Главная страничкаИсходники программСтатьи и описанияПроекты и разработкаПолезные ссылкиЗадай вопрос, получи ответВыскажи свое мнениеПишите письма

Программирование графики

--------------------------------------------------------------------------------

Содержание

Вступление
Немного об эволюции компьютерной графики
О видео картах
Вывод точки
Поумневшая точка
Очистка экрана
Буферизация экрана
Окна (View port)
Работа с палитрой

--------------------------------------------------------------------------------

Вступление

Речь в этой статье пойдет об основах компьютерной графики. На сегодняшний день (2000 год) компьютерная графика достигла столь высокого уровня, что начинающему программисту сложно разобраться в происходящем, и это зачастую отбивает всю охоту программировать компьютерную графику. Ко всему этому добавляется нехватка хоть кокой ни будь информации по этому вопросу не изобилующей сложными терминами и невнятными описаниями самого процесса программирования, к тому же героические фанаты MS WINDOWS дают совсем на мой взгляд бессмысленные рекомендации о использовании готовых библиотек для полноценного использования которых требуется не меньшее знание программирования чем для самостоятельно программирования видео адаптера. Поэтому я решил написать сие творение, дабы новички, да и не только смогли понять принципы программирования графики на IBM PC.


--------------------------------------------------------------------------------

Немного об эволюции компьютерной графики

С начала не было ни чего, и все выводилось на перфоленту.
Затем что-то появилось, но я думаю, это что-то не заслуживает внимания
Потом появилась MDA (Монохромный дисплейный адаптер) который позволял выводить черно-белый текст.
Но текста оказалось не достаточно, и появился CGA (Цветной графический адаптер), этот девайс уже позволял выводить графику по точкам, правда в четырех цветах.
Затем изобрели HERCULES (или до), о его характеристиках я точно не знаю, но в общем-то тоже лажа.
Но и четырех цветной CGA графики народу оказалось маловато, и тогда стараниями фирмы IBM собрали EGA адаптер, который назвали (Расширенный графический адаптер) и он кроме поддержки всего что было раньше позволял выводить графику в расширенных режимах с скажем так высоким разрешением 640*400, и выдавал 16 цветов из палитры в 64 цвета.
Дальше понеслось, для компьютеров PS/2 создали MCGA адаптер, который позволял выводить графику в 256 цветах, правда было маловато оттенков.
Я точно не знаю, но похоже MCGA создала не IBM, и по этому этот гигант решил перехватить рынок, создав VGA адаптер (Видео графическая матрица), который на корню похоронил MCGA, и стал основным стандартом. Основными его характеристиками стали возможность выбора цвета из 262143 оттенков для всех режимов, вывод на экран сразу 256 различных цветов, ну и главной фишкой оказался режим 320*200 256 цветов. (А еще если его юзать с адаптером HERCULES можно было достичь разрешения 1024*768)
На основе VGA адаптера был создан SVGA адаптер (Супер видео графическая матрица) который на сегодняшний день (2000г.) остается одним из основных, и позволяет выводить графику в огромных разрешениях (По сравнению с EGA) и с глубиной цвета до 16777215 оттенков, при этом без ограничения 256 цветами.
Вот так примерно выглядит эволюция графики на PC. Говоря о бедующем, увеличения количества цветов нам не грозит, и сейчас основным направлением развития видео адаптеров стало увеличения скорости обработки данных, увеличение видео памяти и акселерация основных видео функций и 3D графики.


--------------------------------------------------------------------------------

О видео картах

На сегодняшний день (2000г.) на рынке появилось много графических адаптеров, которые так или иначе пытаются нам нахваливать и давать советы о том что именно его мы должны купить. При этом используются страшные заклинания как PCI, AGP, 2D/3D Акселерация и т.д. и т.п. Если вы профи, то да, это вам скажет о многом, но если нет, как разобраться что все это значит и почему GeForce с 64мб DDRDRAM круче S3 3d/2X с 8Мб, чем AGP лучше PCI и т.д. и т.п. Начнем по немножку, AGP, PCI, ISA, это слоты на материнской плате, в которые втыкаются всякие платы (Звук, Видео, Модем ...). Главное различие этих слотов, это скорость обмена данными между устройством и процессором, по этому чем лучше у вас слот, тем быстрее работает ваша видео карта. ISA - Этот разъем использовался еще на 80286 машинах, а может и раньше. Где-то в 90х годах его понемножку начал вытеснять разъем PCI (Бедующие компьютерной техники (см. кино ХАКЕРЫ)) который работал на порядок быстрее, но в погоне за выгодой, да и в целях еще большего разгона видео карт INTEL выпускает в свет AGP стандарт ориентированный на графические карты который позволяет проводить обмен данными между (видео карта) - (процессор) в обход системной шины, что увеличивает производительность еще в несколько раз. Так что для видео карт на данный момент (2000г.) AGP - стандарт является одним из самых наилучших, хотя и PCI еще не потерял свою актуальность.

Видео память - многие считаю что это показатель крутости видео адаптера, но они заблуждаются. Если они используют карту без 3D ускорения, то огромное количество видео памяти им и не потребуется, по этому я не понимаю смысла покупки простой видео карты с 32Мб видео памяти, когда за такие же деньги можно взять VOODOO с 16 Мб. Для того, чтобы понять сколько видео памяти вам нужно, вы должны разобраться в принципе ее распределения в видео адаптере. В 32 битно графике (максимальное количество цветов) на каждую точку (Пиксель) на экране отводится 4 байта, в режиме 1600*1280 мы имеем 2048000 точек, перемножив это на 4 мы получим число нужных нам байт для хранения такого кол-ва информации 8192000байт, далее переведем все это в мегабайты (разделим на 1024 два раза) получим примерно 8 Мб, для работы в WINDOWS нужно чтобы этот объем покрывался 2 раза, то есть нам нужно 16 Мб видео память и 20 дюймовый монитор, но самое интересное то, что вы не такое разрешение использовать не когда не будете, т.к. оно вам и не надо, стандартное разрешение экрана где-то 1024*768 24бит (True Color) в Windows и 800*600 в играх, исходя из этого посчитаем сикока видео памяти нам нужно для удовлетворения этих потребностей


1024*768*3*2 = 4.5 Мб

(В 24 битной графике на 1 пиксель уходит 3 байта)

Видео карта с 6Мб это изврат, но можно сделать вывод, что 8Мб нам хватит выше крыши.

Но сегодня мало карт с просто 2D ускорением, а карты с большим количеством памяти, ну не могут не претендовать на 3D ускорение, и вопят что такое кол-во памяти им нужно для хранения текстур. Тут конечно сложно спорить, все, что у нас остается от вывода графики, программа использует под текстуры, но кто мне объяснит, какое количество и каких текстур нужно загнать в 3D ускоритель, со скажем 32Мб видео памяти, в котором при режиме 800*600 24бита остается свободными более 28Мб.

Еще одним показателем качества видео памяти является ее тип, в простых видео картах используется памяти VRAM, но с ускорением карты, требуется более быстрая память, поэтому в современных картах используется SDRAM, которая гораздо быстрее чем VRAM, ну и SDRAM не предел, сегодня появился стандарт DDRDRAM, который используется в высокопроизводительных 3D ускорителях типа GeForce2. Скорость памяти, это один из ее основных показателей, потому что при работе в режиме 320*200 вам хватит и VRAM, а в режимах скажем 1024*768 карта должна работать с 10 кратным ускорением для того чтобы достичь подобных результатов, и это для режимов с 256 цветами.

Ну ладно, хватит о преимуществах и недостатках, в конце приведем классификацию карт.

Для бедных - 4/2/1 Мб видео памяти VRAM, что-то типа TRIDENT, CIRUS LOGICK или что-то подобное.
Для офиса - 8Мб карта с памятью SDRAM, с 2D ускорением, S3 Virge или Matrox
Игровая - RivaTNT2, VooDoo 3000 или выше. Лучший вариант объединяющий 2D и 3D ускорение.
Рулез - GeForce 2, 32(64)Mb DDRDRAM

--------------------------------------------------------------------------------

Вывод точки

Если вы хоть немного разберитесь в программировании, то вы наверняка использовали стандартные модули для вывода графики как GRAPH. Его прототип есть в Ц и в Паскале. Он дает много возможностей, но не блещет скоростью вывода и мобильностью, требует BGI файл, и в стандартном варианте позволяет работать только с графикой 16-256 цветов и меньше. Ко всему этому, когда смотришь какую-нибудь ДЕМУ, там творят такое, что с модулем граф не когда не сделать.

Первое что нам нужно сделать, это установить нужный нам видео режим. Делается это путем использования прерывания процессора Int 10h (16), где в регистр AH заносим 0, а в регистр AL-номер видео режима.

Program SetMode320*200_256;
Uses Dos;
Var Rp:Registers; {Создаем переменную регистров}
Begin

Rp.Ah:=0;
Rp.Al:=$13; {Номер видео режима, 320*200 256 цветов}
Intr($10,Rp); {вызываем прерывание}

End.


Через это прерывание можно установить все VGA видео режимы, но самый полезный из них это режим $13. С ним просто работать и в нашем распоряжении 256 цветов. Вернуть экран обратно в текстовый режим можно путем вызова того-же прерывания но со значением $3 в регистре Al

Program SetTextMode;
Uses Dos;
Var Rp:Registers; {Создаем переменную регистров}
Begin

Rp.Ah:=0;
Rp.Al:=$3; {Номер стандартного текстового режима, 80*25}
Intr($10,Rp); {вызываем прерывание}

End.

Установив режим мы теперь должны что-то вывести на экран, делается это просто. Информация о содержимом экрана храниться в памяти по адресу $A000 для графики, и $B800 для текста. В Паскале для этого есть две переменные SegA000 и SegB800. Желательно использовать именно их, по тому что в защищенном режиме памяти меняется адресация, и в этих переменных храниться нужное нам значение сегмента. Вот пример вывода чяго ни будь на экран.

Program Demo1;
Uses Dos,Crt;
Var Rp:Registers;
I:Integer;
Begin

Rp.Ah:=0;
Rp.Al:=$3; {Номер стандартного текстового режима, 80*25}
Intr($10,Rp); {вызываем прерывание}
{Выведем что-нибудь на экран}
For i:=0 to 64000 do

Mem[SegA000,i]:=i;

Readkey;

End.

Экран заполниться разноцветными пикселями. Что же произошло. В сегменте SegA000 память отведена для работы с видео адаптером, и когда мы изменяем там значение, оно сразу же изменяется в видео памяти. Данные там храниться построчно, т.е. для режима 320*200 256 цветов первые 320 байт соответствуют первой строке на экране, следующие 320 байт - это вторая строка, и т.д. и т.п. до 200 строки. Теперь не сложно посчитать положение точки на экране, Mem[Y*320+X]:=Col, и если мы по этому смещению установим нужный нам байтик в значение нужного нам цвета, то на экране сразу отобразиться точка, ну и получить точку можно также, но только не установив байт, а прочитав его Col:=Mem[Y*320+X];

Program Demo2;
{Сделаем программу более мобильной, сделаем все в виде процедур}
Uses Dos,Crt;

{Установим видео режим}
Procedure SetMode(N:Byte)
Var Rp:Registers;
Begin

Rp.Ax:=N; {Занесем номер режима}
Intr($10,Rp); {Вызовем прерывание}

End;

{Рисуем точку на экран}
Procedure Pix(X,Y:Integer;Col:Byte);
Begin

Mem[SegA000:Y*320+X]:=Col;

End;

{Получаем точку с экран}
Function GetPix(X,Y:Integer):Byte;
Begin

GetPIx:=Mem[SegA000:Y*320+X];

End;

Begin

SetMode($13); {Установим режим 320*200 256 цветов}
Pix(100,100,15); {Поставим точку на экране по координатам 100,100 цветом 15}
Readkey;
SetMode($3);

End.


--------------------------------------------------------------------------------

Поумневшая точка

Отлично, точку мы поставили, но теперь проведем эксперимент, поставим точку по координатам (321,10), по идеи точка должна попасть за экран, но у нас она выскакивает с другой стороны экрана, как же этого можно избежать. А очень просто, нужно проверять координаты точки перед ее выводом, а делается это так.

Program Demo3;
Uses Dos,Crt;

{Установим видео режим}
Procedure SetMode(N:Byte)
Var Rp:Registers;
Begin

Rp.Ax:=N;
Intr($10,Rp);

End;

{Рисем точку на экран}
Procedure Pix(X,Y:Integer;Col:Byte);
Begin

{Первое берем X и Y как Word, если вдруг придет отрицательное число, то
у нас получиться нечто более 32768, этим мы и воспользуемся}
If (Word(X)<320) And (Word(Y)<200) Then Mem[SegA000:Y*320+X]:=Col;

End;

{Получаем точку с экран}
Function GetPix(X,Y:Integer):Byte;
Begin

If (Word(X)<320) And (Word(Y)<200) Then GetPIx:=Mem[SegA000:Y*320+X];

End;

Begin

SetMode($13); {Установим режим 320*200 256 цветов}
Pix(100,100,15); {Поставим точку на экране по координатам 100,100 цветом 15}
Pix(321,100,15); {Поставим точку на экране по координатам 100,100 цветом 15}
Readkey;
SetMode($3);

End.

Теперь точка не выскакивает за экран, а значит мы можем смело рисовать по любым координатам.


--------------------------------------------------------------------------------

Очистка экрана

Теперь решим следующую задачу, как очистить экран. Первое что приходит в голову, в цикле поставить везде точки одного цвета, но для полного экрана это не очень рационально, т.к. мы делаем 64000 сравнения координат точки, а нам просто надо установить все байты в сегменте $A000, в нужное нам значение. Все это решается очень просто, в Паскале есть функция заполнения данных под названием FillChar, которая эквивалентна STOSB на ассемблере. Делается это так;

Program Demo4;
Uses Dos,Crt;

{Установим видео режим}
Procedure SetMode(N:Byte)
Var Rp:Registers;
Begin

Rp.Ax:=N;
Intr($10,Rp);

End;

Procedure Cls(Col:Byte);
Begin

{Устанавливаем 64000 байт в сегменте $A000 по смещению 0 байт в значение Col}
FillChar(Mem[SegA000:0],64000,Col);

End;

Begin

SetMode($13); {Установим режим 320*200 256 цветов}
Repeat

Cls(Random($FF));

Until Keypressed;
Readkey;
SetMode($3);

End.


--------------------------------------------------------------------------------

Буферизация экрана

Хоть вывод графики у нас и быстрый, но все равно, если у нас будет что-то с полноэкранной прорисовкой, то все это, при прямом выводе на экран будет заметно. Для того, чтобы этого избежать нам нужно использовать буфер в памяти, делается это примерно так, резервируем 64Kb памяти, и выводим не в сегмент $A000, а в сегмент нашего буфера, на который будет указывать специальная переменная, скажем VideoSEG. Заодно решаем, что нам нужно.

1.Переделаем все выше приведенные исподники в модуль

2.Для работы с буфером нам нужно

Переменную указатель на вывод
Процедуру создания буфера
Процедуру вывода буфера
Процедура удаления буфера
Процедура копирования буфер
Процедуры установки вывода в буфер и на экран

3.Немного переписать процедуру вывода точки

Сказано, сделано ...

Unit MYVGA;
Interface

Const

ScreenXres = 320; {Ширина экрана в пикселях}
ScreenYres = 200; {Высота экрана в пикселях}

Var VideoSeg:Word; {Сегмент вывода}

Procedure SetMode(N:Byte); {Установка видео режима}
Procedure Pix(X,Y:Integer;Col:Byte); {Вывести точку}
Procedure GetPix(X,Y:Integer):Byte; {Получить точку}
Procedure Cls(Col:Byte); {Очистка экрана}

Procedure NewB(P:Pointer); {Создать новый буфер в памяти}
Procedure DelB(P:Pointer); {Удалить буфер из памяти}
Procedure SetB(P:Pointer); {Установить вывод в буфер}
Procedure SetS; {Установить вывод на экран}
Procedure OutB(P:Pointer); {Вывести буфер на экран}
Procedure GetB(P:Pointer); {Копировать экран в буфер}
Procedure CopyBB(Src,Dest:Pointer); {Копировать буфер в буфер}

Implementation

{Создаем новый буфер}
Procedure NewB(P:Pointer);
Begin

GetMem(P,$FFFF); {Берем $FFFF байт под буфер в динамической памяти}

End;

{Удаляем буфер из памяти}
Procedure DelB(P:Pointer);
Begin

FreeMem(P,64000); {Освобождаем 64000 байт динамической памяти}

End;

{Установить вывод в буфер}
Procedure SetB(P:Pointer);
Begin

VideoSeg:=Seg(P^); {Видео сегмент равен сегменту нашего буфера}

End;

{Установить вывод на экран}
Procedure SetS;
Begin

VideoSeg:=SegA000; {Видео сегмент равен сегменту экрана}

End;

{Копируем буфер на экран}
Procedure OutB(P:Pointer);
Begin

Move(P^,Mem[SegA000:0],64000); {Копируем 64000 байт из памяти по адресу буфера, в видео сегмент}

End;

{Копируем экран в буфер}
Procedure GetB(P:Pointer);
Begin

Move(Mem[SegA000:0],P,64000); {Тоже что и OutB, но на оборот}

End;

{Копируем буфер в буфер}
Procedure CopyBB(Src,Dest:Pointer);
Begin

Move(Src^,Dest^,64000); {Копируем буфер в буфер}

End;

{Установка видео режима}
Procedure SetMode(N:Byte)
Var Rp:Registers;
Begin

Rp.Ax:=N; {Занесем номер режима}
Intr($10,Rp); {Вызовем прерывание}

End;

{Очистка экрана}
Procedure Cls(Col:Byte);
Begin

{Устанавливаем 64000 байт в сегменте $A000 по смещению 0 байт в значение Col}
FillChar(Mem[VideoSeg:0],64000,Col);

End;

{Рисем точку на экран}
Procedure Pix(X,Y:Integer;Col:Byte);
Begin

{Первое берем X и Y как Word, если вдруг придет отрицательное число, то у нас получиться нечто более 32768, этим мы и воспользуемся}
If (Word(X)<320) And (Word(Y)<200) Then Mem[VideoSeg:Y*320+X]:=Col;

End;

{Получаем точку с экран}
Function GetPix(X,Y:Integer):Byte;
Begin

If (Word(X)<320) And (Word(Y)<200) Then GetPIx:=Mem[VideSeg:Y*320+X];

End;

Begin

VideoSeg:=SegA000; {Устанавливаем вывод на экран}

End.

*********************************************************************************

Program Demo5;
Uses MyVGA,CRT;
Var
Bufer:Pointer; {Переменная буфера}
I,J,K:Integer;

Begin

Writeln('Вывод графики с использованием буфера');
Readkey;
SetMode($13);
NewB(Bufer); {Создаем буфер в динамической памяти}
SetB(Bufer); {Вывод в буфер}
Repeat

For j:=0 to 199 do
For i:=0 to 319 do

Pix(i,j,i+j+k);

Inc(K);
OutB(Bufer); {Выводим буфер на экран}

Until Keypressed;
DelB(Bufer); {Удаляем буфер из динамической памяти}
SetS;
Readkey
SetMode($3);

Writeln('Вывод графики с без использования буфера');
Readkey;
SetMode($13);
Repeat

For j:=0 to 199 do
For i:=0 to 319 do

Pix(i,j,i+j+k);

Inc(K);

Until Keypressed;
Readkey;
SetMode($3);

End.

P.S. Так как мы все делаем в модуле, я буду писать отдельные процедуры и ф-ции для модуля, дабы сократить размер текста.


--------------------------------------------------------------------------------

Окна (View port)

Еще одна штука, которая нам может пригодиться, это вывод не на весь экран, а в окно (окно - прямоугольная область экрана). При этом начало координат экрана переноситься на начало окна, а вывод за его приделы не как не отражается на экране. Для вывода в окно, нам нужно создать переменные задающие координаты окна, и дающие размер окна, а также переменную флаг, которая будет говорить нам о том, что вывод производится в окно. Еще нам придется немного дополнить процедуры PIX, GETPIX и CLS.

Unit MYVGA;
Interface

Const
.... Предыдущие константы ....

Var
.... Предыдущие переменные ....
WLX,WLY:Integer; {Координаты левого верхнего угла окна}
WHX,WHY:Integer; {Координаты правого нижнего угла окна}
WXRES,WYRES:Integer; {Ширина и высота окна}
WEnabled:Boolean; {Если True то вывод в окно}

.... Процедуры описанные ранее ...

Procedure Pix(X,Y:Integer;Col:Byte); {Вывести точку}
Procedure GetPix(X,Y:Integer):Byte; {Получить точку}
Procedure Cls(Col:Byte); {Очистка экрана}

Procedure SetWindow(X,Y,X1,Y1:Integer); {Установить вывод в окно}
Procedure SetScreen; {Установить вывод на весь экран}
Function MaxX:Integer; {Ширина окна или экрана}
Function MaxY:Integer; {Высота окна или экрана}

Implementation

{Установить вывод в окно}
Procedure SetWindow(X,Y,X1,Y1:Integer);
Begin

If X>X1 Then Begin WLX:=X1;WHX:=X End Else Begin WLX:=X;WHX:=X1 End;
If Y>Y1 Then Begin WLY:=Y1;WHY:=Y End Else Begin WLY:=Y;WHY:=Y1 End;
WXres:=WHX-WLX+1;
WYres:=WHY-WLY+1;
WEnabled:=True;

End;

{Установить вывод на весь экран}
Procedure SetScreen;
Begin

WEnabled:=False;

End;

{Ширина окна или экрана}
Function MaxX:Integer;
Begin

If Enabled Then MaxX:=WXres Else MaxX;=ScreenXres;

End;

{Высота окна или экрана}
Function MaxY:Integer;
Begin

If Enabled Then MaxY:=WYres Else MaxY;=ScreenYres;

End;

{Очистка экрана}
Procedure Cls(Col:Byte);
Begin

If WEnabled Then Begin

WEnabled:=False;{Этот маленький фокус поможет нам выиграть пару тактов у процессора}
{Конечно грубо, но эффективно}
For j:=WYL to WYH do
For i:=WXL to WXH do
Pix(i,j,Col);
WEnabled:=True;

End Else FillChar(Mem[VideoSeg:0],64000,Col);

End;

{Рисуем точку на экран}
Procedure Pix(X,Y:Integer;Col:Byte);
Begin

{Проверяем, а выводим ли мы в окно}
if WEnabeld Then

{Далее смотри, а не выходим ли мы за рамки окна}
If (Word(X)<WXres) And (Word(Y)<WYres) Then Begin

{Если нет, то пересчитываем координаты для экрана}
Inc(X,WLX);
Inc(Y,WLY);

End Else Exit; {Иначе выходим из процедуры}

If (Word(X)<ScreenXres) And (Word(Y)<ScreenYres) Then
Mem[VideoSeg:Y*320+X]:=Col;

End;

{Получаем точку с экран}
Function GetPix(X,Y:Integer):Byte;
Begin

if WEnabeld Then
If (Word(X)<WXres) And (Word(Y)<WYres) Then Begin

Inc(X,WLX);
Inc(Y,WLY);

End Else Exit;
If (Word(X)<ScreenXres) And (Word(Y)<ScreenYres) Then
GetPIx:=Mem[VideSeg:Y*320+X];

End;


.... Процедуры описанные ранее в которые не были внесены изменения ...
Procedure SetMode(N:Byte); {Установка видео режима}
Procedure NewB(P:Pointer); {Создать новый буфер в памяти}
Procedure DelB(P:Pointer); {Удалить буфер из памяти}
Procedure SetB(P:Pointer); {Установить вывод в буфер}
Procedure SetS; {Установить вывод на экран}
Procedure OutB(P:Pointer); {Вывести буфер на экран}
Procedure GetB(P:Pointer); {Копировать экран в буфер}
Procedure CopyBB(Src,Dest:Pointer); {Копировать буфер в буфер}

Begin

VideoSeg:=SegA000; {Устанавливаем вывод на экран}

End.

*********************************************************************************

Program Demo6;
Uses MyVGA,CRT;
Var
Bufer:Pointer; {Переменная буфера}
I,J,K:Integer;

Begin

Writeln('Вывод графики в окно');
Readkey;
SetMode($13);
SetWindow(10,10,100,100);
NewB(Bufer); {Создаем буфер в динамической памяти}
SetB(Bufer); {Вывод в буфер}
Repeat

For j:=0 to MaxY-1 do
For i:=0 to MaxX-1 do

Pix(i+Trunc(Sin((j+k)*0.05)*20),j,i+j+k);

Inc(K);
OutB(Bufer); {Выводим буфер на экран}

Until Keypressed;
DelB(Bufer); {Удаляем буфер из динамической памяти}
SetS;
Readkey;
SetMode($3);

End.


--------------------------------------------------------------------------------

Работа с палитрой

При работе с 256 цветовыми режимами или как это иногда называется 8 битной графикой, в нашем распоряжении 256 цветов. При этом все это вместе называется палитрой. Оттенок каждого цвета состоит из трех компонент RGB (Красный, Зеленый и Голубой) в пределе от 0 до 63. Задать его можно двумя способами, через БИОС и через порты ($3C7, $3C8, $3C9). Так как, через БИОС все работает почему-то тормазнуто, лучший сделать все это через порты, пример чего я привожу ниже.

Желательно эти процедуры вставить в модуль MyVGA

{Процедура установки RGB}
Procedure SetRGB(N,R,G,B:Byte);
Begin

Port[$3C8]:=N; {В порт $3C8 посылаем номер цвета в палитре}
Port[$3C9]:=R; {В порт $3C9 последовательно посылаем компоненты R, G, B}
Port[$3C9]:=G;
Port[$3C9]:=B;

End;

{Получение значений RGB для цвета N}
Procedure SetRGB(N:Byte;Var R,G,B:Byte);
Begin

Port[$3C7]:=N; {В порт $3C7 посылаем номер цвета в палитре}
R:=Port[$3C9]; {Из порта $3C9 последовательно считываем компоненты R, G, B}
G:=Port[$3C9];
B:=Port[$3C9];

End;

*********************************************************************************

Program Demo7;
Uses MyVGA,CRT;
{В MyVGA должны быть прописаны процедуры GetRGB и SetRGB}
Var
I,J,K:Integer;
Begin

Writeln('Пример работы с палитрой');
Readkey;
SetMode($13);
For j:=0 to MaxY-1 do
For i:=0 to MaxX-1 do

Pix(i+Trunc(Sin((j+k)*0.05)*20),j,i+j+k);

Readkey;
{Изменяем значения палитры}
For i:=0 to 255 do

SetRGB(i,i,i,0);

Readkey;
SetMode($3);

End.


Rambler's Top100