Jól hangzik nem?

Ez a név annyit takar, hogy egy egész képet forgatunk a képernyőn, közben meg még zoomolgatunk is. Persze ez a kép (továbbiakban textura) végelenítve van. Szóval gondoljuk meg:

Csináljunk olyat, hogy forgassuk az egész képet. Jobb esetben azt a csekély 320*200=64000 pontot, amit ugyi mi látunk. Ez nem biztos, hogy olyan nagyon gyorsan fog menni realtime. Ez nem nyert. Most jön a csel: ha a a képet nem tudjuk forgatni a képernyôn, forgassuk a képernyôt a képen. (Persze a monitor a helyén maradhat) Ez esetben a hatás ugyanaz. Aki nem érti, rajzoljon egy képet, majd vágjon ki papírból egy akkora téglelapot amekkora a kép, (ez a képernyô) ezt forgassa a képen, és próbáljon vele együtt forogni. (egészségügyi okok miatt max 45 fok ajánlott).
 

 
A négyezetrács a végtelenített textúrát hivatott jelképezni, az elforgatott négyszög pedig a képernyôt. Az x,y -al jelölt sarok a képernyô bal felsô sarka. 0,0 -val a textúra közepét jelöljük, a további számítások során ezt tekintjük origónak. A textúra bal felsô sarka azért -160,100, mert az egyszer?ség kedvéért egy 320X200-as textúrát forgatunk. (A felbontás is 320X200 lesz) Tehát mi látszik az ábrábán? Elôször is az, hogy baromi ronda, mert paintbrushban készült, ráadásul feleakkorában, mint itt látszik. Ezen túl még annak is kéne látszani, amit szemléltetni akar, az pedig a képernyô elforgatása a textúrán.

Ha az egész képernyôt texture mappingelni akarjuk elôször azt kéne tudni, hogy honnan kell kezdeni. Tehát a képernyô bal felsô sarkának a helyét a végtelenített textúrán. Ez az x,y. Az ábráról jól láthatóan az (x,y) a (-160,100) ból származtatható egy a szög? elforgatással.

A függvénytáblában találunk is egy képletet, ami asszongya, hogy pont origó körüli forgatása:

u=x*cos(a) +y*sin(a)

v=-x*sin(a) +y*cos(a)

tehát esetünkben:

x=-160*cos(a)+100*sin(a)

y=160*sin(a)+100*cos(a)
 

Na, azt már tudjuk, hogy honnan indulunk. Tehét benn álunk az elsô scanline elején, és haladni kéne a textúrán. A scanline minden egyes pontjához meg kellene találni az általa takart textúrakoordinátát. Be kell vezetni egy pár uj értéket.

tex0x,tex0y Tulajdonképpen a képernyô bal oldala által leírt egyenest

tex0xstep,tex0ystep határozzák meg a textúrán, errôl az egyenesrôl indul minden scanline

texx,texy a scanline adott pontjának textúrakoordinátája

texxstep,texystep scnaline-on belüli lépésköz a textúrán

Szóval a scanline-on belül minden egyes pontnál texxstep-et lépünk a textúrán x irábnyba, texystep-et lépünk y irányba, és az aktuális értéket tároljuk a texx-ben, meg a texy-ban. A texx, és texy által meghatározott textúrapontot rakjuk ki a képernyôre.

A Scanline-ok kezdetét hasonlóképpen határozzuk meg, tex0xstep -el, és texoystep-el lépegetünk, tex0-ben és texy0-ban tároljuk az aktuális értéket.

Ezeket viszont ki is kéne számolni.

Az ábráról látszik, hogy a képernyô bal oldala (90-a) szöget zár be a vízszintessel. Tehát:

tex0xstep=cos(90-a)=-sin(a)

tex0ystep=sin(90-a)=cos(a)

Az meg már egyenesen magától értetôdô, hogy a scanline-ok a szöget zárnak be a vízszintessel. Tehát:

texxstep=cos(a)

texystep=sin(a)

Ennek fényében átírhatjuk a képletet, ami a kezdôpontot határozza meg:

texx0=-160*texxstep-100*texx0step;

texy0=-160*texystep-100*texy0step;

Akkor már tudunk minden értéket. Elvileg m?ködik is, de mi ennyivel nem elégszünk meg. Zoomolni is akarunk. Egyszer?. Csak a zoomolás arányában kell növelni a lépésközöket. A Zoomolást vezérlô paraméter legyen dist

tex0xstep=-sin(a)-sin(a)*dist

tex0ystep=cos(a)+cos(a)*dist

texxstep=cos(a)+cos(a)*dist

texystep=sin(a)+sin(a)*dist

Aztán még egy pár simítás:

Mivel a valóságban a textúra közepe sohasem lesz 0,0 , csak a bal felsô sarka, ezért módosítsuk a képletet tetszôleges középpontra, a textúra valódi középpontjait pedig rakjuk be mán egy konstansba:

texx0=x-XCENTER*texxstep-YCENTER*texx0step

texy0=y-XCENTER*texystep-YCENTER*texy0step

Ennyi lenne az elméleti alap. Ezek a képletek persze a gyakorlatban nem teljesen így m?ködnek. Azaz nagyon is jól m?ködnének, ha lebegôpontosan számolnánk. De ez helyett, inkább a már megszokott megoldást választjuk. Pár bittel feljebb nyomjuk az értékeket.(fix pontos számolás). Ez a pár bit általában 8 vagy 16, attól függôen, hogy mekkora értékeket kell tárolnunk, és hány byte-on. Itt nálam most 8. A szögfüggvényeket, pedig, mint az már természzetes táblázatból vesszük.

void wallpaper (int x, int y, int dist, int rot)

{
int texx,texy,texxstep,texystep; //scanlinenon belul
int texx0,texy0,texx0step,texy0step; //scanlineok kozott
int line,xpos;

char *scp; //screen pointer

scp=screen;

rot&=511;

//scanline-on beluli lepeskoz a texturan:
texxstep=cost[rot]+((cost[rot]*dist)>>8); //8 bit fel
texystep=sint[rot]+((sint[rot]*dist)>>8); //8 bit fel
//scanline-ok kozti lepeskoz a texturan:
texx0step=-sint[rot]-((sint[rot]*dist)>>8); //8 bit fel
texy0step=cost[rot]+((cost[rot]*dist)>>8); //8 bit fel

//bal felso sarok melyik texturapont:
texx0=(x<<8)-XCENTER*texxstep-YCENTER*texx0step; //8 bit fel
texy0=(y<<8)-XCENTER*texystep-YCENTER*texy0step; //8 bit fel
//vegtelenites

while (texx0<0) texx0+=TEX_X_SIZE*256;
while (texy0<0) texy0+=TEX_Y_SIZE*256;
while (texx0>=TEX_X_SIZE*256) texx0-=TEX_X_SIZE*256;
while (texy0>=TEX_Y_SIZE*256) texy0-=TEX_Y_SIZE*256;
for(line=0;line<200;line++)

{
texx=texx0;
texy=texy0;
for(xpos=0;xpos<320;xpos++)
{

*scp=map[(texy >> 8)*TEX_X_SIZE+(texx >> 8)]; //texture map -> screen
scp++;
texy+=texystep;
texx+=texxstep;
if (texx<0) texx+=TEX_X_SIZE*256; //vegtelenites
if (texy<0) texy+=TEX_Y_SIZE*256;
if (texx>=TEX_X_SIZE*256) texx-=TEX_X_SIZE*256;
if (texy>=TEX_Y_SIZE*256) texy-=TEX_Y_SIZE*256;
}

texy0+=texy0step;
texx0+=texx0step;
if (texx0<0) texx0+=TEX_X_SIZE*256; //vegtelenites
if (texy0<0) texy0+=TEX_Y_SIZE*256;
if (texx0>=TEX_X_SIZE*256) texx0-=TEX_X_SIZE*256;
if (texy0>=TEX_Y_SIZE*256) texy0-=TEX_Y_SIZE*256;
}
}

Ennyi lenne a code C-ben.

Annyit tud, hogy tetszôleges középpont körül forgat egy 320X200-as textúrát, tetszôleges zoomolással, tetszôleges fokban.

Persze elég lassú, de nálam még pont jól megy. Azon kívül, hogy nem assembly, még egy pár hibája azért van. pl.: a scanline-ok kezdôpontjait el lehetne tárolni egy tömbben, és ebbôl dolgozni. Sokkal rövidebb, és gyorsabb belsô ciklust eredményezne. Ezen kívül Ha nem 320X200-as textúrát használna, hanem 256X256 -ost akkor nem kellene álandóan végtelenítgetni, hiszen ha byte-on tárolnánk a cuccokat, azok maguktól körbeforognának. Aztán lehetne törôdni a képernyô torzításával is, igaz ez csak 1.2 ebben a video módban, de akkor is szebb lenne.

Valamit az olvasóra is kell hagyni.

Persze a program megint Watcom C-ben sikerült, valahogy nem fekszik nekem a Borland. Ebbôl kifojólag, ha netán valaki megpróbálja átírni az int-eket cserélje long int-re, mert a watcom 4 byte-os integerekkel számol.

A program a képet egy pcx-bôl veszi. Ennek részletes leírását nem tartottam szükségesnek, de, ha valakit érdekel a pcx normális beolvasása (ez a program csak 320X200X256-osat at tud kezelni) , vagy bármi más, megkérem írjon mán valamit!

CSÁ
 

Kimmel Tamás
eMail:PC-XUser@IDG.HU, Subject: "DEMO rovat"
KUMM@MI.STUD.PMMFK.JPTE.HU