e-mail    Debatní kniha    Mapa stránek    Hlavní  
 perličky 
 

Efekty s paletou 256 barev

Pavel Pospíšil

aneb -- Nekonečně mnoho způsobů, jak nastavit paletu
Jistě si vzpomínáte na minulou zimu, kdy Bajt otiskoval seriál příspěvků od různých autorů o využití 256 barev na videokartě VGA. Stránky Bajtu zaplňovaly variace na téma ,,Nekonečně mnoho způsobů, jak nakreslit bod". Naštěstí těch účelných způsobů zase až tak moc není (vím přibližně o jednom), takže invence autorů se po čase vyčerpala. (,,Vezměte adresu bodu na obrazovce, přičtěte k ní 52, odečtěte 100 a 12, přičtěte 60 a máte výslednou adresu...")

V tomto článku vás nechci ohromovat žádnými geniálními algoritmy, které byste stejně vymysleli mnohem lépe sami. Snad ale vezmete zavděk jedním dosud nepublikovaným (alespoň kam až sahají moje čtenářské obzory), pročež snad i skoro neznámým způsobem, jak nastavit paletu. Nutno dodat, že i velice rychlým, a pro některé efekty s paletou naprosto nepostradatelným. Přišel jsem na něj zkoumáním programů, které uměly to, co já tehdy ne (což je činnost ,,podlá" a už vůbec ne tvůrčí, ale občas přináší výsledky.)

Pro nastavení palety existují funkce BIOSu. Kupodivu nikoli rychlé a mnohdy ani ne moc praktické. Moc kouzel se s nimi dělat nedá. Pokud jste ale někdy viděli nějaké crackerské demo, anebo koneckonců i skoro jakoukoli hru, všimli jste si možná různých barevných efektů, jako třeba postupné zesvětlování nebo ztmavování obrázku, přechod barev jednoho odstínu do odstínu jiného, atakdále atakpodobně. Tady jsme s BIOSem opravdu v koncích. Ale jak na to jít? Samozřejmě přes porty.

Důležité jsou pro nás tři z nich, adresované 03c6h, 03c8h a 03c9h. Před tím, než chceme začít nastavovat barvy, na port 03c6h pošleme hodnotu 255 a tím dáme kartě tuto skutečnost na vědomí. Potom už jenom stačí na port 03c8h posílat číslo barvy, kterou měníme (0--255), a na port 03c9h vyslat postupně za sebou hodnoty jednotlivých barevných složek pro danou barvu v pořadí R, G, B. Pro další barvu pak už stačí jenom zase poslat její číslo, potom hodnoty barevných složek...atd. Registry DAC pro jednotlivé barevné složky jsou šestibitové, takže nemá příliš smysl posílat na ně větší hodnotu, než 63 -- to jen tak na okraj.

Co takhle si to nejdříve vyzkoušet na jednom jednoduchém a docela praktickém příkladu? Řekněme, že chceme, aby prvních 64 barev byly odstíny šedé. Pokud bychom se o totéž snažili BIOSem, máme dvě šance -- buď by nám to zabralo zbytečně moc času (okolo pěti sekund), nebo bychom k tomu potřebovali, já vím, sice jenom trošku paměti -- hmm, ale komu v dnešní době bude chybět 196 bajtů... -- a i tak je tento druhý BIOSovský způsob o kapku pomalejší. (See TechHELP & try! Přerušení 010h, služba 010h, podslužby 010h a 012h.) Procedura GreyPalette je s tím hotová vmžiku.

A co když chceme paletu postupně ztmavit až do ztracena? Tady už BIOS vůbec nestačí. Jako ukázka možného řešení slouží procedura DarkPalette. Jejím parametrem je ukazatel na pole hodnot R, G, B pro jednotlivé barvy původní palety - celkem tedy 768 bajtů. Použitý algoritmus není nejdokonalejší -- podívejte se, jak barvy při ztmavování zároveň zešednou. Vymýšlení lepšího algoritmu ponechám na vás; smyslem tohoto článku je především uvést technické detaily, jak na to. U návěští snow si všimněte, že se čeká na zpětný běh paprsku. Pokud nastavujete paletu jen jednou, nic asi nepostřehnete. Pokud víckrát za sebou (což vlastně procedura DarkPalette dělá), bude vám dojem kazit sněžení známé z monitorů CGA. Aby dojem nekazilo, musíme paletu nastavovat vždy při zpětném běhu paprsku. A to je vše. Přeji vám mnoho úspěchů při vašich vlastních full color experimentech.

unit palette;
interface

procedure GreyPalette;
procedure DarkPalette(palette : pointer);

implementation

procedure GreyPalette;assembler;
{ Nastavení prvních 64 barev palety na odstíny šedé }
asm
        mov dx,03c6h         {inicializace nastavování}
        mov al,0ffh
        out dx,al
        mov cx,64          {budeme nastavovat 64 barev}
        mov bl,0     {číslo aktuálně nastavované barvy}
    @nextcolor:
        mov dx,03c8h    {vyšlu číslo nastavované barvy}
        mov al,bl
        db 2eh                    {pro jistotu počkáme}
        out dx,al
        inc dx  {dx=3c9h=port pro vyslání hodnot R,G,B}
        mov al,bl     {u odstínů šedé mají všechny tři}
                      {barevné složky stejnou hodnotu,}
                      {proto stačí, když ji přenesu do}
                             {al jen jednou na začátku}
        db 2eh                    {pro jistotu počkáme}
        out dx,al                   {vyslání hodnoty R}
        db 2eh                    {pro jistotu počkáme}
        out dx,al                   {vyslání hodnoty G}
        db 2eh                    {pro jistotu počkáme}
        out dx,al                   {vyslání hodnoty B}
        inc bl                 {zvýším pro další barvu}
        loop @nextcolor                {další barva...}
end;

procedure DarkPalette(palette : pointer);assembler;
{ Ztmavovani palety }
asm
        push ds     {TurboPascal potřebuje ds zachovat}
        lds si,palette   {ds=seg.palety, si=ofs.palety}
        mov bh,0ffh  {bh - hodnota (vlastně počitadlo)}
                                              {odstínů}
        mov dx,03c6h         {inicializace nastavování}
        mov al,0ffh
        out dx,al
    @dark:
        push si   {schováme, protože budeme potřebovat}
                      {pro každý další průchod smyčkou}
        mov bl,0         {v bl číslo nastavované barvy}
        cld               {df=0 => lods.. půjde nahoru}
        mov al,4     {kvůli sněžení jsme rozdělili 256}
                           {barev na čtyři části po 64}
    @quarter:
        push ax
        mov dx,03dah    {počkáme na zpětný běh paprsku}
    @snow:
        in al,dx
        test al,8
        jz @snow
        mov cx,40h                 {64 barev * 4 = 256}
    @nextcolor:
        mov dx,03c8h    {vyšlu číslo nastavované barvy}
        mov al,bl
        out dx,al
        inc bl                 {zvýším pro další barvu}
        inc dx  {dx=3c9h=port pro vyslání hodnot R,G,B}
        lodsb               {načteme původní hodnotu R}
        cmp al,bh   {porovnáme ji s aktuálním odstínem}
        jc @no_r  {pokud je hodnota aktuálního odstínu}
                   {větší, než původní hodnota barevné}
                {složky, vezmeme ještě původní hodnotu}
        mov al,bh                 {jinak už ztmavujeme}
    @no_r:
        shr al,1 {hodnoty R,G,B jsou pouze 6-bitové...}
        shr al,1
        out dx,al                   {vyslání hodnoty R}
        lodsb                       {totéž platí pro G}
        cmp al,bh
        jc @no_g
        mov al,bh
    @no_g:
        shr al,1
        shr al,1
        out dx,al
        lodsb                 {...a samozřejmě i pro B}
        cmp al,bh
        jc @no_b
        mov al,bh
    @no_b:
        shr al,1
        shr al,1
        out dx,al
        loop @nextcolor                {další barva...}
        pop ax
        dec al
        jnz @quarter                {další čtvrtsmyčka}
        pop si {vyzvednu schované SI pro další průběh }
        sub bh,4 {hodnotu odstínu zmenšit o 4 - zkuste}
                               {sem dát třeba 1, 2 ...}
        jnc @dark      {ztmavujeme, dokud to obrazovce}
                  {úplně nevytmavíme (haha!)-erhmmm...}
        pop ds  {vyzvednu schovaný DS - kvůli Pascalu }
end;

begin
end.



Pascal - hlavní
Překladače
Vlastní články
Převzaté články
Věci na stáhnutí
Odkazy k tématu
BP7 buglist
Chyba Run-time 200

BASIC