int21h

Grafika v Turbo Pascalu 7

Vítejte v dalším seriálu. Už předem Vám mohu slíbit, že bude určitě delší než všechny předchozí díly seriálů dohromady, což Vás jistě potěšilo. Tentokrát to snad nebude tak nudné, jelikož začneme první část multimédií - vizuální stránku. Pokud byste nechtěli čekat na tu druhou (zvukovou), můžete se podívat na mé stránky (www.volny.cz/martinlux), kde najdete nejen spoustu programů, které využívají XMS či grafiku, ale je tam také titulkovací program (ten možná až od dubna 2006), který obsahuje obsazení přerušení, vlastní funkce na textovou grafiku a klávesnici (takže si můžete ověřit své znalosti z minula), ale hlavně obsluhu zvukové karty pod DOSem, což by se Vám mohlo líbit.

Naučíme se postupně od těch nejjednodušších věcí, jak v 320x200 a 256 barvách změnit paletu (a také jak vytvořit nějaké ty efekty), přečíst a rozsvítit pixel, jak udržovat virtuální obrazovku. Poté přejdeme postupně k vyšším režimům s přepínáním bank-switch (až 1024x768 v True Color barvách (24/32 bitů), budeme brát ale i 15/16 bitové), naučíme se optimalizace, nastavovat logickou délku řádků, pracovat s EMS a XMS pamětí, načítat obrázky BMP ve všech možných kvalitách a formátech, vytvoříme si svůj vlastní grafický formát podporující RLE kompresi a průhlednost, a také formát pro animace včetně komprese. Naučíme se převádět barvy mezi HC a TC, a mezi TC a 256 barvami. Ukážeme si, jak na 256 barevném režimu zobrazovat v reálném čase filmy, které jsou True Colorové. Zjistíme, jak se počítá průhlednost, průsvitnost a změna jasu, jak natočit nebo převrátit obrázek. Mezi jinými se také okrajově zmíním o kreslení čar, kružnic, čtverců a obdelníků, a také se naučíme vyplňování. A také se samozřejmě naučíme pracovat s textovými režimy a ukážeme si práci se dvěma monitory, pokud jeden z nich je VGA a druhý MDA/Hercules. A v příštím seriálu se dozvíme, jak naše poznatky převést z TP7 do Free Pascalu, kde využijeme i tzv. Linear Frame Buffer, a později ještě Direct Draw. Nuže, tolik na úvod a teď se dáme do práce...


Na začátek trochu obecných informací: co se týče kódů v mých příkladech, tak je pro zjednodušení píši skoro bez kontrol. Ovšem pro úplně nejlepší program je vhodné jej zkompilovat s {$I-} přepínačem a testovat vše pomocí IOResult (nemluvě o testech, zda proměnná má správný obsah). Readln funkce se dnes už nepoužívají, protože se během nich nedá dělat nic jiného, takže si přetečení meze či zadání písmena do čísla můžeme snadno ošetřit při použití funkce Readkey, která s pomocí Keypressed nezdržuje program a můžeme zatím dělat něco jiného. Vaše příklady by mohly vypadat např. takto:


type SString = string[50];
var Buffer : array[0..2,0..5] of SString;
    Soubor : file;
    SkutRW : integer;
    i : word;
    p : byte;


function UpString(Retez : SString) : SString;
var i : byte;
begin 
 if Retez[0] <> #0 then
  for i := 1 to Length(Retez) do
   Retez[i] := UpCase(Retez[i]);
 UpString := Retez;
end;


procedudure Zpracuj(var Neco : array of SString);
var i : word;
begin
 for i := Low(Neco) to High(Neco) do
 {..nějaký kód..}
end;


{$I-}
begin
 if ParamStr(1) = '' then Exit;
 Assign(Soubor,ParamStr(1));
 Reset(Soubor,1);
 if IOResult = 0 then
 begin
  i := 0;
  while not Eof(Soubor) do
  begin   
   BlockRead(Soubor,Buffer[i],SizeOf(Buffer[i]),SkutRW);
   if (SkutRW <> SizeOf(Buffer[i])) and not Eof(Soubor) then {chyba!};
   for p := 0 to 5 do
   begin
    Buffer[i][p] := UpString(Buffer[i,p]);
    Zpracuj(Buffer[i,p]);
   end;
   Inc(i);
   if i = 3 then Break;
  end;
  Close(Soubor);
  if i = 0 then Exit; {chyba! nic nenačteno}
 end;
end;  

Doufám, že tento "kratičký" kód Vám poskytl alespoň nějaké nastínění, co a kde by se mohlo/mělo kontrolovat. Samozřejmě můžeme být puntičkáři a kontrolovat kde co, ale ideálně se dělá jen to, co nás zajímá a co známe. Ono se časem něco "podělá" dalšího, takže budeme kontroly stejně přidávat podle toho, na co se náš program stane náchylným. Vhodné ovšem je nejen chyby hlásit a pak padat, ale také se je spíše snažit automaticky opravovat (tam, kde to jde). A teď už konečně na hlavní náplň:



TEXTOVÝ REŽIM:
--------------

Asi si říkáte, že v textu už dneska téměř nikdo nepracuje. Není to pravda. Nejen totiž, že textový režim je o dost rychlejší a na paměť méně náročnější než grafický, a tedy pro jeho provozování stačí i pomalejší počítač, stále se používá např. i v Linuxu a různých konzolích. Navíc, existují i lepší režimy než 80x25. Pomocí VESA se můžete dostat klidně i na 132x60. V takovém rozlišení se dá už i dobře kreslit (a to nejen pomocí ASCII artu, ale i pomocí plných znaků, nebo jen pomocí mezer s barvou pozadí), protože se jedná o grafický režim 1056x960 (popř. ?x840) a přitom to spotřebuje jen 16 kB paměti (žádné přepínání banků). Takovéto rozlišení (132x60) používají navíc i některé LCD displaye u mikropočítačů nebo u mobilních telefonů, takže se to hodí i pro emulaci (nehledě na fakt, že by to samozřejmě šlo emulovat i v grafickém režimu).

Nejprve trocha teorie. Textový mód je první, ve kterém počítač startuje. Jeho video paměť je na adrese $b800 a může být velká až 32 kB. Ve standardním módu 80x25 (a prakticky i ve všech ostatních) se využívají 2 byty na znak (první je ASCII kód znaku a druhý je atribut, tj. barva popředí, barva pozadí, blikání), takže na celou obrazovku stačí jen 4000 bytů. Proto většina karet podporuje tzv. stránky (mohla by to být obdoba Lixových násobných pracovních ploch), kde můžete mít až několik obrazovek a jen mezi nimi přepínáte (aniž byste je museli mazat a znovu kreslit). Textový režim standardně podporuje 16 barev, tj. 16 barev pro barvu znaku. Pro barvu pozadí je standardně jen prvních 8 barev, protože nejvyšší bit z tohoto 4 bitového údaje určuje blikání (není-li zakázáno).

Výjimkou jsou MDA karty a karty Hercules. Jejich textová paměť začíná na adrese $b000, ale má také jen 4000 bytů na stránku (některé z nich podporují jen 1). Opět se používají 2 znaky na atribut, ale význam atributu je jiný. Protože tyto adaptéry umí jen 3 barvy od jednoho odstínu (a ten určuje monitor, ne Vy), tak se v atributech nastavuje něco jiného. Bit 7 znamená opět blikání nebo vyšší intenzitu barvy (u VGA se tam také určuje nejvyšší bit pro barvu pozadí, pokud je povoleno 16 odstínů) pro pozadí (tj. plné). Bit 3 nastaven na 1 zvýrazní barvu znaku (2x vyšší intenzita). Pokud jsou ostatní bity 0, je to atribut mezery. Pokud je kromě b7 a b3 (které mohou mít vždy různou hodnotu) nastaven jen bit 1, bude Váš znak podtržený. Normální znak docílíte tak, že první tři bity budou vždy 1, ostatní nula (kromě 7 a 3, samozřejmě). A inverzní znak má zase jedničkové bity 6-4. Atribut pro barevné znaky probereme později (VGA totiž umožňuje i dva fonty současně, kdy zase přijdete o 1/2 barev popředí). A jinak, textový režim se obvykle zobrazuje v 50 Hz. Videokarta CGA textový režim neumí. A pokud se divíte, proč probírám takovou zastaralost, je to proto, že i karta VGA umí emulovat MDA (režim má číslo 7, viz. ATHelp).

Protože jsme minule odhodili jednotku CRT, mohou nám nyní chybět některé její užitečné funkce. Některé z nich můžeme přepsat přímo do assembleru s využitím VGA BIOSu (na DOS nebo obyčejný BIOS se můžeme předem vykašlat). Nebudeme ale schopni dodržet přesnou konvenci, pokud si nenapíšeme i další funkce. Protože se nehodlám zabývat pomalými řešeními, zmíním se o možnosti využít VGA BIOS jen okrajově (jeho úplný popis můžete najít v AThelpu):


procedure Write(Co : string; Atr : byte); assembler;
asm  
	les	di,co
	mov	dx,es:[di]
	inc	di
	mov	ah,9
	xor	bh,bh
	mov	bl,atr
	mov	cx,1
@pis:	mov	al,es:[di]
	int	10h
	inc	di
	dec	dx
	jnz	pis  
end;  

procedure ClrScr; assembler;
asm  
	mov	ax,3
	int	10  
end;  

procedure GotoXY(X,Y : byte); assembler;
asm  
	mov	ah,2
	xor	bh,bh
	mov	dh,y
	mov	dl,x
	dec	dh
	dec	dl
	int	10h  
end;  

My se ovšem budeme zabývat něčím mnohem rychlejším. Následující kódy se dají prakticky použít bez úprav (nebo jen s menšími úpravami) i ve Free Pascalu (max. tam, kde je kód v Pascalu se musí namísto PORT použít OutPortX nebo InPortX a tam, kde se adresuje v ASM dosová paměť (v TP7 vždy) se musí segment+offset sloučit do jednoho 20 bitového údaje, hodit do 32 bitového registru EDI, atd. a použít FS registr jako "segmentový"). Nyní využijeme znalosti teorie a uděláme si základní funkce pro obsluhu textového režimu. Videopaměť se dá adresovat následujícím způsobem:


var	TextMemory : array[1..80,1..25] of record
						Znak : char;
						Atr : byte;
					   end absolute $b800:0;  

Nám se toto pole bude celkem hodit (jinak bychom museli využít příkaz MEM), ale převážně jen ve funkci ClrScr. Také si ale budeme muset definovat další své proměnné, které budeme využívat:


var	X,Y : byte;
	Barva : byte;
	Pozadi : byte;  

A nyní už můžeme přistoupit k daným funkcím. Předpokládám, že k jejich pochopení nejsou zase až tak složité, takže se jistě nebudete zlobit, když je nebudu popisovat (konstanty typu RED, WHITE, atd. si zkopírujte z nápovědy TP7 a nezapomeňte na jméno BLINK = 128, které se používá u TEXTCOLOR). Trochu si doplníme teorii. V barevných režimem má BYTE atribut toto složení:


bppp zzzz


Kde "b" je bit blikání (1=bliká), "p" je barva pozadí a "z" je barva popředí. Pokud se blikání nepoužívá, tak nejvyšší nible se změní na "pppp". Definujeme si proto proměnnou, která nám bude indikovat, zda je blikání povoleno či nikoliv (při startu programu ji inicializujte na TRUE) a pak hned půjdeme na ty procedury:

var	Blikani : boolean;


procedure GotoXY(_X,_Y : byte);
begin
 X := _X;
 Y := _Y;
end;


function WhereX : byte;
begin
 WhereX := X; 
end;


function WhereY : byte;
begin
 WhereY := Y;
end;


procedure ClrScr;
begin
 FillChar(Mem[$b800:0],4000,0);
{FillChar(TextMemory,SizeOf(TextMemory),0);}
end;


procedure TextColor(_B : byte);
begin
 Barva := _B; 
end;


procedure TextBackGround(_B : byte);
begin
 Pozadi := _B;
end;


procedure Write(Co : string);
var i : byte;
    ofs : word;
    atr : byte;
    v : byte;
begin
 ofs := (word(Y)*80+X) shl 1;
 if Blikani then
  atr := (barva and $8f) or ((pozadi and 7) shl 4)
   else atr := (barva and $f) or ((pozadi and $f) shl 4);
 for i := 1 to Length(Co) do
 begin
  Mem[$b800:ofs+i shl 1] := Co[i];
  Mem[$b800:ofs+i shl 1+1] := Atr;
 end;
 V := Ord(Co[0]);
 Inc(X,Length(Co);		{řetězec může zabrat i více než 1 či 2 řádky}
 while X > 80 do		{pokud nechceme psát řetězce za sebe, toto můžeme}
 begin				{klidně odstranit. Pak se bude chování této WRITE}
  if Y < 25 then Inc(Y);	{lišit od té v Turbo Pascalu}
  X := (X+V)-80;
  V := 0;
 end;
end;


procedure ZmenBlikani(Stav : boolean);
begin
 Blikani := Stav;
 asm  
	mov	bl,blikani
	mov	ax,1003h
	int	10h  
 end;
end;  

Věřte, nevěřte, toto je všechna ta magie. Všechno, co se navíc nastavuje přes INT 10h, jde nastavit i přes I/O porty karty. Proč se to tak nedělá? I když je to rychlejší, některé věci (změna rozlišení) tím jdou hůře a navíc u některých novějších karet se riskuje, že jejich kompatibilita s VGA není taková, jaká by měla být. Jejich ovladač (obyčejný ASM kód VGA BIOSu navěšený na INT 10, který pak přistupuje ke kartě přes IO porty) sice podporuje INT 10h, ale sama karta už neemuluje některé staré VGA porty. Ostatní funkce, které případně budete potřebovat, si můžete dostavět sami (např. Window není nic jiného, než přidání podmínek na oblast do procedury WRITE).

Na začátku jsem se zmínil o možnost více stránek. Tato možnost je velmi jednoduchá. budeme potřebovat proceduru, která změní aktivní stránku, proceduru, která přepne stránku, do které my budeme psát (nic nám samozřejmě nebrání, abychom psali do té samé, která je zrovna aktivní) a jednu proměnnou. Bude nutné také upravit proceduru Write tak, aby počítala s možností více stránek (max. čtyři). Každá stránka začíná na STR*4000:


var	Stranka : byte;		{nastavte na začátku na 0}


procedure ZmenStranku(_stranka : byte); assembler;
asm  
	mov	al,_stranka
	and	al,3
	mov	stranka,al  
end;


procedure ZmenAktivni(_stranka : byte); assembler;
asm  
	{na začátku programu je už standardně na 0}
	mov	al,_stranka
	and	al,3
	mov	ah,5
	int	10h  
end;


procedure Write(Co : string);
var i : byte;
    ofs : word;
    atr : byte;
    v : byte;
begin
 ofs := stranka*4000+(word(Y)*80+X) shl 1;
 if Blikani then
  atr := (barva and $8f) or ((pozadi and 7) shl 4)
   else atr := (barva and $f) or ((pozadi and $f) shl 4);
 for i := 1 to Length(Co) do
 begin
  Mem[$b800:ofs+i shl 1] := Co[i];
  Mem[$b800:ofs+i shl 1+1] := Atr;
 end;
end;		{chybí zde posun souřadnic}  

Pokud se na to cítíte, můžete použít možnost VGA karty zobrazovat dva fonty současně. Zaveďte si jednu novou proměnnou (na začátku jí dejte na FALSE), další dvě pro typ fontu (nastavte je na začátek na 0 a 1), novou proceduru a upravte jednu stávající:


var	DvaFonty : boolean;
	KteryFont : byte;
	Font : array[0..1] of byte;


procedure StavFontu(Zapnuto : boolean);
begin
 DvaFonty := Zapnuto;
 if Zapnuto then
 asm  
	mov	ax,1103h			{viz. ATHelp}
	les	di,font
	mov	bl,es:[di]
	inc	di
	mov	bh,es:[di]
	shl	bh,2
	or	bl,bh
	int	10h  
 end else
  asm  
	mov	ax,3+128			{resetujeme nastavení}
	int	10h				{ale nevymažeme obrazovku!}  
  end;
end;


procedure TextFont(Druhy : boolean);
begin
 KteryFont := Ord(Druhy);
end;


procedure SetFont(Ktery,Typ : byte);		{vybereme typ fontu}
begin						{máme 2 banky, pro každý 1 ze 4 typů}
 Ktery := Ktery and 1;
 Typ := Typ and 3; 
 Font[Ktery] := Typ;
end;


procedure Write(Co : string);
var i : byte;
    ofs : word;
    atr : byte;
begin
 ofs := stranka*4000+(word(Y)*80+X) shl 1;
 case DvaFonty of
  False : if Blikani then
           atr := (barva and $8f) or ((pozadi and 7) shl 4)
            else atr := (barva and $f) or ((pozadi and $f) shl 4);
   True : if Blikani then
           atr := (barva and $87) or ((pozadi and 7) shl 4) or (kteryfont shl 3)
            else atr := (barva and $7) or ((pozadi and $f) shl 4) or (kteryfont shl 3);
 end;
 for i := 1 to Length(Co) do
 begin
  Mem[$b800:ofs+i shl 1] := Co[i];
  Mem[$b800:ofs+i shl 1+1] := Atr;
 end;
end;  

Dané fonty si můžete do paměti nahrát přes funkce na INT $10. Protože jsou popsané v ATHelpu a protože tuto možnost zmiňuji jen jako bonus (zase tak moc často ji určite používat nebudete, kdy potřebujete 512 různých znaků? Pokud na něco ano, jistě jste tak daleko, že v textovém režimu provádíte mnohem lepší věci než jen snahy o výměnu fontů), nebudu se o tom dále zmiňovat. Snad jen poznámka na konec: všechno, co jsme doposud dělali, bylo určeno pro režim 80x25 v 16 barvách (ty můžete změnit, ale narozdíl od 256 barev je to poněkud složitější: vložíte index barvy do BL a voláte funkci $1007 (samozřejmě na INT 10h); pak hodnotu BH uložíme do BL a BH vynulujeme, do AX dáme 1010h, a do CH,CL,DH uložíme G,B,R hodnoty barvy (význam má jen dolních 6 bitů) a voláme INT 10h). Pod číslem 1 máte režim 40x25 a pod režimem 7 je MDA. Je proto vhodné si zavést proměnnou a namísto pevného čísla 3 do AX vkládat tuto proměnnou, aby Vám program fungoval ve všech režimech (je samozřejmě také nutné upravit funkci WRITE, kde stačí jen změnit výpočet offsetu (popř. ještě atributu pro MDA - ostatní funkce můžete ponechat, snad kromě GOTOXY, pokud měníte "rozlišení"), vše ostatní přijde "jaksi samo"). Pokud byste chtěli jiné režimy, musíte už používat VESA funkce. Ty budeme rozebírat v grafickém režimu, takže jen ukážu, jak se inicializují (bez nějakých kontrol). Všechny režimy mají jen 16 barev a jsou to tyto čísla: $108 (80x60), $109 (1320x25), $10A (132x43), $10C (132x50) a $10D (132x60); samozřejmě spotřebují také více paměti VRAM (X*Y*2):


function VESA(rezim : word); assembler;
asm  
	mov	ax,$4f02
	mov	bx,rezim
	int	10h  
end;  

Pokud ale nechcete využívat VESA režimy, ukáži Vám něco, co by mělo fungovat na všech (VGA kompatibilních) grafických kartách. Možná si někteří z Vás vzpomínáte, že např. M602 dokázal zobrazovat (a nejen on, třeba i Turbo Pascal IDE) ne jen na 25 řádcích, ale i na 50. Jak se to dělá? K této činnosti potřebujeme znát něco o I/O portech grafické karty (doporučuji AThelp). Nás budou zajímat hlavně CRT registry. Nejprve trocha té teorie. Porty jsou ve dvojicích, na první zapíšete číslo registru, který chcete číst, a ze druhého přečtete jeho hodnotu, popř. jí do něj zapíšete. Protože jsou porty hned za sebou, je možné při zápisu namísto posílání 2xBYTE poslat 1xWORD, který se pošle do obou portů současně (resp. postupně). Pokud chcete ale číst, musíte to provést nadvakrát a navíc s mírným spožděním. Je také dobré vědět, že pokud chcete změnit některý bit, nemůžete zapsat jen jeho hodnotu do bytu a ten pak poslat, protože bychom tím změnili i hodnoty ostatních bitů, a to nechceme! Já jsem si původně myslel, že se tyto režimy nastaví v registru 17 bitem 2, ale když jsem psal proceduru, tak jsem sice nastavil bit 2, ale v registru 9 (chyba) a ono to také nějak fungovalo. Inu, dějí se divné věci. Tak tedy začneme první procedurou, která dělá přesně to opačné, co nechceme. Takže namísto 25 řádků dostaneme řádků 12:


procedure PolovicniPocet; assembler;
asm  
	mov	al,9		{CRT registr číslo 9}
	mov	dx,$3d4		{výběr CRT portu}
	out	dx,al		{pošleme číslo registr}
	inc	dx
	jmp	@spozd
@spozd:
	in	al,dx		{přečteme původní stav z dalšího portu}
	mov	ah,al
	mov	al,9
	or	ah,128		{nastavíme bit 7, tedy dvojité mikrořádkování}
	dec	dx
	out	dx,ax  
end;  

To je sice pěkný efekt, ale asi to není to, co hledáme (jinak je to obdoba režimu 40x25, jenže my jsme si udělali 80x12). Já jsem ale během pokusů a omylů přišel na jeden zajímavý trik. Zjednodušíme si horní proceduru


procedure ZmenaMikroRadku(Lines : byte); assembler;
asm  
	mov	al,9
	mov	ah,lines
	add	ah,128
	dec	dx
	out	dx,ax  
end;  

Pokud nastavíte 7 mikrořádků jako parametr, dostanete standardní 80x25. Pokud dáte třeba 8, dostanete 80x22. Při 9 to bude už 80x19. Dané číslo totiž znamená počet mikrořádků na jeden znak. Tj. logicky, čím vyšší číslo, tím méně řádků na obrazovce. Pokud nastavíte více, tak ve Windows dostanete více řádků, ale ve Full Screen nebudou zobrazeny celé znaky. Protože bit7 je standardně 0, zkusíme jej také "odstranit":


procedure ZmenaMikroRadku(Lines : byte); assembler;
asm  
	mov	al,9
	mov	ah,lines
	dec	dx
	out	dx,ax  
end;  

Bum bác! Když si teď nastavíte 7 mikrořádků, dostanete 80x50! Jediný problém je v tom, že standardní procedury Write nebo Writeln pracují stále jen v řádcích 1-25, jakoby bylo nastavené Window. Pomocí funkce MEM se ale můžeme dostat kamkoliv. Např. Mem[$b800:49*80*2] := Ord('X') zapíše znak X na první znak posledního řádku. Ale pokud přepneme do Full Screen, tak zase nevidíme všechny mikrořádky. Vidíme jen 1/2 písmen a zase navíc v rozlišení 80x25. Abychom to srovnali, musíme dát počet řádků 14, ale to jsme zase tam, kde jsme byli před tím. Možná, že je to vina Windows nebo karty, kdo ví. Možná by stačilo jen změnit font z 8x14 na 8x8 (viz. ATHelp) a dostali bychom o 50% více řádků s normálním textem (namísto 14 mikrolinek by stačilo jen 8). Inu, tady už legrace končí. Pro jednou nám to nevyšlo :-). Zkusíme tedy, jestli nám nepomůže VGA BIOS. Zdá se, že ano. Nějaké funkce na INT 10h zdá se jsou. Ale ty už bohužel v ATHelpu nenajdete. Doporučuji se podívat na Internet, např. na:

http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html

Kde najdete kompletní seznam všech přerušení a jejich služeb. Věřte nebo ne, ale jsou toho megabajty čistého textu. Pokud se Vám to nechce číst jako mě, tak prostě věřte, že do 50 řádkového režimu se dostanete takto:

procedure _50lines; assembler;
asm  
	mov	ax,1202h
	mov	bl,30h
	int	10h
	mov	ax,1112h
	xor	bl,bl
	int	10h  
end;  

A všechny ty hrůzy, co jsme doteď napáchali, odstraníte (resp. se přepnete zpět do 80x25) pomocí inicializace textového módu. Pokud přitom nechcete mazat obrazovku, napište to takto:


procedure _25lines; assembler;
asm  
	mov	ax,83h
	int	10h  
end;  

Na závěr ještě jedna perlička, která se dá (většinou) použít i v grafických režimech a někdy i pod Windows (ale jen ve spuštěné DOSové aplikace). Např. jako spořič monitoru. Jednoduše vypnete zobrazování paměti VRAM (psát do ní ovšem můžete dál):


procedure Zobrazovani(Aktivni : boolean); assembler;
asm  
	mov	ah,12h
	mov	al,aktivni
	mov	bl,36h
	int	10h  
end;  

No, a to je z textového režimu všechno. Na co se dneska asi tak hodí? Buď na prvotní výpisy, než se Váš program hodí do grafiky, na paměťově nenáročné a rychlé aplikace, atd. Můžete si tento režim ještě vylepšit tak, že si zavedete tzv. VVRAM, nebo-li virtuální video RAM. Jedná se defakto o něco jako Page Flipping ve Windows. Z definice TextMemory smažte vše co se týká ABSOLUTE a funkce Write a ClrScr realizujte zápisem do této paměti. Protože RAM je mnohem rychlejší než VRAM (nemluvě o jejím čtení), můžete takto urychlit vykreslování (nehledě na synchronizaci se zpětným během, o kterém se také zmnímíme u grafiky). Až vše vykreslíte, přesunťe celý blok do VRAM pomocí instrukce:

	Move(TextMemory,Mem[$b800:stranka*4000],SizeOf(TextMemory)).
Ale o tomto se budeme zmiňovat později v grafických operacích, takže pokud Vás to zajímá, pokračujte ve čtení tohoto článku... Ještě ale než zavítáme do grafiky, řekneme si jak využít dva monitory. Je to dost stará záležitost, takže pokud nemáte někde starý Hercules, můžete na to zapomenout (samozřejmě, že je možné, abyste používali 2 VGA karty ISA (kde můžete použít jejich I/O porty) nebo PCI (či AGP a PCI, kde už to není tak jednoduché) jak v reálném, tak chráněném režimu, ale to už není taková legrace - je to totiž docela složité. Musíte hlavně zkopírovat BIOS jedné karty jinam a volat jeho funkce přímo a ne přes INT 10h, kde sídlí jen a pouze primární karta; pokud máte v systému primární kartu AGP a sekundární PCI, doporučuji se podívat na stránky www.asm32.com, kde máte k dispozici ovladač (bohužel shareware), který z PCI karty udělá jakoby MDA - dělá se to tak, že změníte jeden bit v North Bridge, takže most pak přesměrovává přístup do paměti $b000 a některé porty na kartu PCI namísto na kartu AGP - ono je to samozřejmě o trochu složitější).

Celé je to vlastně velice primitivní. VGA karta se bude v systému chovat jako primární, tedy na ní uvidíte MS-DOS, hry, budete moci používat její textový režim ($b800) i grafiku ($a000), funkce LFB, INT 10h, BS. Sekundární karta (v tomto případě Hercules) by měla být BIOSem inicializována do textového režimu. A to je také to jediné, co potřebujete (pokud chcete grafiku, tak si musíte s kartou popovídat přes I/O porty). Její paměť je Vám nyní přístupná na $b000, takže cokoliv tam zapíšete se ihned zobrazí. Zjistit, které karty máte v systému se dá přes funkci $1a00 na přerušení $10, kde se Vám v BL a BH vrátí aktivní a neaktivní systém. Ideálně by měl mít registr BX hodnotu $0108. Pro více informací viz. ATHelp, nebo se také můžete podívat na mé stránky, kde je spousta programů týkajících se práce (nejen) v textových režimech (a to i tehdy, pokud program pracuje i s grafikou).



POKRAČOVÁNÍ PŘÍŠTĚ V GRAFICKÉM REŽIMU...

2006-11-30 | Martin Lux
Reklamy: