Gruzińskie Noce 06, czyli Nerdy Nights po polsku
« dnia: Maj 25, 2016, 13:13:59 »
Tej nocy: nauczmy się teraz wyświetlać nieruchome tło.

Tło
trzy cztery składniki potrzebne do generowania tła w NES'ie. Pierwszy to paleta kolorów tła, z której wybiera się kolory dla elementów tła na ekranie. Drugi to nametable mówiący o samym układzie kolorów układzie Tilesów na ekranie i układzie atrybutów, które zawierają tylko numery palet, nie "kolory", trzeci - attribute table - przypisuje kolory z palety do miejsc na ekranie. Ostatnim elementem są same grafiki, które chcemy wyświetlić.

Paleta Tła
Tak jak dla sprite'ów tak i dla tła jest osobna, 16-kolorowa paleta. W naszym poprzednim programie ładowaliśmy paletę, ale jeszcze nie była używana. Żeby zobaczyć te kolory można użyć PPU Viewer w FCEUXD SP. 

Nametable
Tak jak i sprite'y, tak i obrazy tła składają się z tile'ów 8x8 pikseli. Rozdzielczość obrazu to 32 x 30 tile'ów, czyli 256 x 240 pikseli. W systemie PAL wyświetlany jest pełen obraz. W NTSC ucinanych jest 8 górnych i 8 dolnych poziomych linii co daje po okrojeniu 256x224. Dodatkowo same telewizory mogą nie wyświetlać kilku górnych lub dolnych wierszy.
 
Jeden ekran pełen tile'ów tła nazywany jest nametable'm. NES posiada wewnętrzny RAM połączony z PPU, który starcza na dwa nametable. Będziemy używać tylko jednego obrazu w tym poradniku. Nametable będzie się zaczynał u nas w PPU od adresu $2000 i zajmować będzie 960 bajtów (32x30). Nametable można podejrzeć przez FCEUX SP w Nametable viewerze.

Tabele atrybutów (Attribute Tables)
Tabele atrybutów są prawdopodobnie najtrudniejszą rzeczą do zrozumienia, a poza tym ustanawiają wiele ograniczeń grafiki. Każdy z Nametable'i ma tabelę atrybutów, która ustala które kolory z palety będą określane w danej sekcji/części ekranu. Attribute Table jest przechowywana w tym samym wewnętrznym RAMie co Nametable. Będziemy używać tego, który zaczyna się w PPU pod adresem $23C0 ($2000+960). 

Po pierwsze ekran podzielon jestże na siatkę o kratkach 32x32 pixele, czyli 4x4 tile. Każdy bajt w Atribute Table ustala grupę kolorów (0-3) w palecie tła, która będzie używana w tym obszarze. Obszar ten jest dalej podzielony na cztery mniejsze kratki o wymiarach 2x2 tile. Dwa bity wchodzące w skład jednego bajta tabeli atrybutów są przypisane do każdej kratki 2x2.
To rozmiar jednego bloczku cegieł w SMB. To ograniczenie oznacza, że tylko 4 kolory (z jednej grupy kolorów) mogą być użyte w każdym z pikseli w kwadracie/obszarze tła o rozmiarach 16x16 pikseli. Sekcja z zieloną rurą w SMB nie może używać koloru czerwonego, bo już są wykorzystuje 4 kolory.

Rzut okiem na przykładowy obraz z SMB. Nałożona siatka 4x4 tile, na dole pokazane palety kolorów


Siatka ma 8 kwadratów w poziomie, więc będzie 8 bajtów atrybutów poziomo. Potem każdy z tych pól siatki jest podzielony na sekcje po 2x2 tile, żeby stworzyć bajt atrybutowy:


Żaden obszar z 16x16 pixeli nie może używać więcej niż 4 kolory. Żodyn! Dla czepliwych cwaniaków: chyba, że spojrzymy na obszar zahaczający o sąsiednią 'kratkę', albo pojawią się w nim sprite'y.



Wrzucanie danych
By ustawić grafikę tła, twoje dane muszą być określone w ROMie twym przy użyciu dyrektywy .db Tego nie ma w ROMie, tak się załącza ciąg danych w pliku źródłowym dla kompilatora. Co więcej, różne kompilatory używają różnych dyrektyw, np. ASM6 używa ".byte" zamiast ".db". Niektóre edytory graficzne tworzą te dane, ale tu zrobimy je ręcznie. Dla przykładu przerobimy tylko kilka linii.Używamy tego samego CHRa z SMB. Wpierwej definiujemy dane nametable'a, każdy wiersz grafiki dzielimy dla naszej wygody na dwa 16 bajtowe fragmenty:

nametable:

  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;wiersz 1
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;samo niebo ($24 = niebo)


  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;wiersz 2
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24  ;;samo niebo


  .db $24,$24,$24,$24,$45,$45,$24,$24,$45,$45,$45,$45,$45,$45,$24,$24  ;;wiersz 3
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$53,$54,$24,$24  ;;kilka górnych części cegieł


  .db $24,$24,$24,$24,$47,$47,$24,$24,$47,$47,$47,$47,$47,$47,$24,$24  ;;wiersz 4
  .db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$55,$56,$24,$24  ;;kilka dolnych części cegieł


Potem określane są dane z attribute table. Każdy bajt obejmuje obszar 4x4 tile zatem potrzebnych nam będzie tylko 8 bajtów. W kodzie binarnym łatwiej jest edytować 2 bity na obszar 2x2 tile'i.
 
attribute:

.db %00000000, %00010000, %0010000, %00010000, %00000000, %00000000, %00000000, %00110000
 
 
I na koniec, używna jest ta sama paleta kolorów co w SMB:
palette:
.db $22,$29,$1A,$0F, $22,$36,$17,$0F, $22,$30,$21,$0F, $22,$27,$17,$0F
 
Tak jak przy poprzednim wczytywaniu palet, stosowana jest pętla do skopiowania określonej liczby bajtów z pamięci do PPU. Najpierw adres PPU jest ustawiany jako początek nametable w miejscu $2000. Potem kopiowane jest nasze 128 Bajtów danych tła. Następnie adres PPU jest ustawiany na początek tabeli atrybutów w miejscu #23C0 i kopiowanych jest 8 Bajtów.

LoadBackground:
LDA $ 2002             ; wczytaj stan PPU żeby zresetować wysoki/niski zatrzask
LDA #$20
STA $ 2006             ; zapisz wysoki bajt adresu $2000
LDA #$00
STA $ 2006             ; zapisz niski bajt adresu $2000
LDX #$00 ; zacznij w 0
LoadBackgroundLoop:
LDA background, x ; wczytaj dane z adresu (background + wartość x)
STA $ 2007 ; wpisz do PPU
INX ; X = X + 1
CPX #$80 ; Porównaj X do hex'a $80, dziesiętnie 128 - kopiowanie 128 Bajtów
BNE LoadBackgroundLoop ; Odgałąź do LoadBackgroundLoop jeśli porównanie wyszło różne od zera
                        ; jeśli porównanie było równe 128, kontynuuj niżej
 
 
 LoadAttribute:
LDA $ 2002             ; wczytaj stan PPU żeby zresetować wysoki/niski zatrzask
LDA #$23
STA $ 2006             ; zapisz wysoki bajt adresu $23C0
LDA #$C0
STA $ 2006             ; zapisz niski bajt adresu $23C0
LDX #$00 ; zacznij w 0

LoadAttributeLoop:
LDA attribute, x ; wczytaj dane z adresu (attribute + wartość w x)
STA $ 2007 ; zapisz do PPU
INX ; X = X + 1
CPX #$08 ; Porównaj X do hex'a $08, dziesiętnie 8 - kopiowanie 8 Bajtów
BNE LoadAttributeLoop
 
Ostanie zmiany to rozkazanie PPU by używał grafik Pattern Table 0 dla sprite'ów, a Pattern Table 1 dla tła.

LDA #%10010000 ;aktywuj NMI, sprite'y z Pattern 0, tłao z Pattern 1
STA $2000

Aktywuj renderowanie tła:
LDA #%00011110 ; aktywuj spritey, aktywuj tło
STA $2001
 
Wyzeruj pozycję przesunięcia ekranu:
 
LDA #$00
STA $2005
STA $2005
(zapis $2005 tylko zmienia pozycję przewinięcia ekranu (pierwszy zapis zmienia przesunięcie poziome, drugi pionowe)
 
Podsumowując:
http://www.nespowerpak.com/nesasm/background2.zip
Pobierz i rozpakuj background2.zip. Powyższy kod znajuje się w pliku background.asm.  Upewnij się, że pliki mario.chr oraz background.bat są w tym samym folderze NESASM, potem dwuklik w background.bat.  Włączy się NESASM i powinien utworzyć plik background.nes.  Otwórz go przez FCEUXD SP żeby zobaczyć tło. Zmień region w emulatorze na PAL, żeby ujrzeć cały ekran.
 
Wszystkie fragmenty tła jakich nie zapisałeś będą wciąż używać tile'a 0, który to jest numerem 0 w grafikach SMB. Spróbuj dodać więcej nametable'i i danych atrybutów do sekcji .db, potem zmień pętle tak, by kopiowały więcej Bajtów do pamięci RAM PPU. Możesz też spróbować zmieniać adres startowy w PPU dla nametable'i tabel atrybutów, by przesunąć je kilka wierszy niżej.



Literatura uzupełniająca:
Oryginał [ENG]:
Nerdy Nights week 6

Podręcznik ASM 6502 dla Atari [PL]:
http://atarionline.pl/biblioteka/materialy_ksiazkowe/Asembler%206502%20(v2).pdf