Pixeles függőleges scroll hardveresen Sikerült, ebből az idén 35 éves gépből, még egy hardveres finomságot kicsikarni, amit tudtommal eddig egyik TVC-s játék vagy felhasználói program sem valósított meg. Ez pedig a függőleges hardveres scroll pixelesen. A demonstrációhoz felhasználtam Sáránszki Misi egyik átpixelezett képét utólagos köszönettel. A SZÓKÖZ billentyű lenyomására láthatóvá válik a trükk egy része, aminek segítségével megvalósítottam ezt az effektet. Ekkor a keret is átvált kékre, hogy még jobban látható legyen az a képernyő „anomália” alul és felül, amit egyébként elrejtek, hogy tökéletes legyen a pixeles scroll illúziója. A SZÓKÖZ újbóli lenyomására ismét „normál” módra vált a scroll. 50 Hz-re állított képernyőn lesz tökéletesen úszó a scroll, ha emulátoron nézitek. De honnan is jött ez az egész és hogy is működik? Akiket érdekelnek a technikai részletek, azoknak itt van viszonylag hosszan kifejtve. Amikor 2019 decemberében elkezdtem a Fuss! című játékot fejleszteni és ennek kapcsán a CRTC-vel történő scrollozás lehetőségeit vizsgáltam, akkor már nyilvánvaló volt az a tény, hogy a képernyőt vízszintesen legkevesebb 1 byte-al lehet így eltolni (scrollozni) és legkevesebb 4 pixelsorral függőlegesen. A függőleges scrollra remek példa az 1985-ös fejlesztésű Szánkóverseny című játék. Oda jó is volt ez a sebesség, amit a képernyő tartalmának minden frissítésekor történő 4 pixelsornyi scrollozása jelentett. De nekem jött egy másik játékötletem, amihez ez már túl gyors lenne. Ha viszont a lassabb mozgás miatt nem scrolloznék minden képernyőfrissítéskor, akkor ez a szép folyamatos scroll döcögőssé válna, mert látszódnak, hogy 4 sorokat ugrik a képernyőtartalom. De a CRTC lehetőségeit nézegetve született egy elméletem, ami alapján az 1 pixelsoronkénti függőleges scroll is megvalósíthatónak tűnt. Persze kell hozzá egy bűvésztrükk, vagyis egy kis illúzió. :) Az elmélet alapja a CRTC R5-ös regisztere, amiben a kiegészítő TV sorok számát lehet megadni. Ez ugyan nem kifejezetten a függőleges szinkronizálásra szolgál, de csodálatos módon egyel módosítva a gyári értéket az egész képernyő 1 pixelnyit mozdul el a kerethez képest és így a képernyőt tudjuk függőlegesen mozgatni. Tehát nem a képernyő tartalmát mozgatja, ahogy a hardveres scrollozáshoz használható R12-es és R13-as regiszterek teszik, hanem az egész képernyőt a keret rovására. Az R5-ös regiszter alapértéke 2, amit ha 1-re állítunk, akkor a megjelenített képernyő felfelé mozdul egy pixelnyit, ami által fent egy pixellel kisebb lesz a keret. Ha 3-ra állítjuk, akkor lefelé mozdul el egy pixelnyit, ugyanennyivel csökkentve az alsó keret méretét. Az R5-ös regiszternek 0-31 közötti értékeket lehet beállítani, ahol a 0 nem sokban ér el a gyári értéktől, 28 esetén viszont már alul kilóg a kép, 31-nél meg aztán még inkább. Oké, el tudjuk mozgatni 1 pixellel az egész képernyőt, de hát ebből nem lehet scrollt csinálni: 1. mert a hülye is látni fogja, hogy nem a képernyő tartalma scrollozódik, hanem maga az egész képernyő mozdul el függőlegesen; 2. meg aztán nem is lehet csak 31 pixelnyit elmozdítani a képernyőt, ha 0-t vesszük kiindulási pontnak, szóval ez scrollozni nem jó. És ez így igaz is. De mivel a CRTC-vel 4 pixelsoronkénti scrollt tudunk csinálni, elég ha az 1-2-3 pixelnyi elmozdulásokat végezzük el az R5-ös regiszterrel és a 4. pixelsornyi elmozdulást már az ismert módon oldjuk meg. Hogy mi? Szóval a scrollozást felosztjuk 4 lépésre: 1. R5-tel elmozdítjuk a képernyőt egy pixelsornyit. 2. R5-tel elmozdítjuk a képernyőt még egy pixelsornyit (már 2 pixelt mozdult el) 3. R5-tel elmozdítjuk a képernyőt még egy pixelsornyit (már 3 pixelt mozdult el) 4. R5-öt visszaállítjuk alapértékre és R12, R13-mal elmozdítjuk a képernyő tartalmát 4 pixelsornyit (vissza 3-at, előre 4-et = +1 - ezzel lesz meg a 4. pixelsornyi elmozdulás) És ezt ismételjük folyamatosan. Aztaaaaaaaaaaa, pixelenként scrollozódik a képernyő! :) Ezzel a második problémánkat megoldottuk, mivel csak 0-3 értékek között használjuk az R5 regisztert, de az elsőt nem. Mégpedig hogy 1-2-3 pixelnyit elmozdul az egész képernyő, majd vissza az alapállapotba, amit a képernyő nagy részén nem is vennénk észre, hiszen az elmozdulás az elmozdulás, elhiszi a szemünk, de a felső és alsó 1-2-3 sorokban ez látható képernyő mozgást és vibrálást okoz, mert ott a képernyő szélei miatt észreveszi a szemünk a turpisságot. Akkor nem tehetünk mást, mint amit a bűvészek is csinálnak, hogy elrejtjük a nézők szeme elől a trükköt. :) Képernyő teteje Mivel 3 sornyit mozgatunk „kamu” módszerrel, így ezt a 3 sort kellene elrejtenünk a nézők szeme elől. Erre a legegyszerűbb módszer, hogy a felső 3 sort ugyanolyan színűre állítjuk, mint a keretet, mintha az egyébként a kerethez tartozna, nem is a képernyőhöz. Ez persze csak az első lépés, nézzük akkor ugyanúgy a 4 lépéses folyamatot: Előkészítés: R5-tel a legmagasabb pozícióba helyeztük a képernyőt (0-s érték nálam, praktikus okokból). Az első 3 sort ugyanolyan színűre állítjuk, mint a keretet. 1. R5-tel egy pixellel lentebb mozdítjuk a képernyőt (1-es érték). A 3. sorba kitesszük az éppen bescrolozandó új sort, mintha az lenne valójában a képernyőnk első sora. 2. R5-tel még egy pixellel lentebb mozdítjuk a képernyőt (2-es érték). A 2. sorba kitesszük az éppen bescrolozandó új sort, mintha az lenne valójában a képernyőnk első sora és mivel fizikailag 1 pixelsorral lentebb került a képernyő, ez most pont ugyanott van, mint az előbbi fázisban a 3. sor. 3. R5-tel még egy pixellel lentebb mozdítjuk a képernyőt (3-as érték). Az 1. sorba kitesszük az éppen bescrolozandó új sort, mintha az lenne valójában a képernyőnk első sora, ami az előző pontban leírtak alapján fizikailag az első sor helyén van ismét. 4. R5-öt alapértékbe állítjuk (0-s érték), ezzel 3 sorral fentebb rántjuk az egész képernyőt. R12-R13-mal 4 pixelsornyit elmozdítjuk a képernyő tartalmát lefelé (és utána hozzá állítjuk a cursor-megszakítás pozícióját is), tehát a 3 sorral történő visszamozgatás és a 4 sorral történő lefelé scrollozás összességében 1 pixellel mozdította ismét el a képernyőt a szemünk számára. Viszont mivel 4 sorral lentebb került a képernyő tartalma az első 3 sort ismét keret színűre kell színeznünk, hogy ne derüljön ki a trükkünk. Ezt követően a 4. sorba (ami a néző számára vizuálisan a legfelső sor) kitesszük az éppen bescrolozandó új sort. Képernyő alja A következő lépéseket a fentiekkel együtt kell elvégezni, csak nem akartam egy bekezdésbe belezsúfolni a képernyő tetején és alján elvégzendőket. Hasonló módon kell elrejtenünk a trükköt alul is, mint ahogy felül csináltuk, csak egy kicsit fordítva. Előkészületre nincs szükség, mert amikor a legmagasabb pozícióba tesszük a képernyőt az R5-tel, akkor a képernyő utolsó sora az utolsó sor, amit megmutatunk, szóval az úgy okés. 1. R5-tel egyel lentebb mozgattuk a képernyőt (1-es érték), de hogy ez alul ne tűnjön fel, az utolsó sort keret színűre állítjuk, mintha „kiscrollozódott” volna az utolsó sor a képről. 2. R5-tel még egy pixellel lentebb mozdítjuk a képernyőt (2-es érték), ezért most az utolsó előtti sort is keret színűre kell állítani. 3. R5-tel még egy pixellel lentebb mozdítjuk a képernyőt (3-as érték), így most alulról a 3. sort is keret színűre kell állítani. 4. R5-öt alapértékbe állítjuk (0-s érték), ekkor alul nincs dolgunk, minden oké, mivel ezzel egy időben az R12-R13-mas regiszterekkel elmozdítottuk lefelé 4 pixelsornyit a képernyőt, így a korábban letakart sorokra odakerül a felettük levő sorok tartalma. És majdnem kész! Merthogy közben még kezelnünk kell, hogy az R12-R13-mal elmozdított képernyővel együtt mozgassuk a képernyő tetejét és alját mutató változóinkat, valamint azt, ami mutatja, hogy felül hová kell kitenni az éppen bejövő új sort. De aztán tényleg csak ennyi és kész is van a függőleges pixeles hardver scroll. Nem nagy dolog, szóval nem is értem, hogy nem jutott ez eszemben 30 évvel ezelőtt