Gruzińskie Noce 04, czyli Nerdy Nights po polsku
Gruzińskie Noce 04, czyli Nerdy Nights po polsku
« dnia: Maj 25, 2016, 13:13:38 »
Tej nocy: umiesz napisać program na Pegasusa? To coś chociaż wyświetl!

Palety
Zanim wyświetlimy coś na ekranie, najpierw trzeba ustawić kolory palet. Istnieją dwie osobne palety, każda po 16 bajtów. Jedna używana do tła, druga do sprite'ów. Bajt w palecie odpowiada jednemu z 64 podstawowych kolorów, które NES jest w stanie wyświetlić. $0D jest zły i nie powinien być używany, bo telewizor może mieć problemy z pokazaniem 'czarniejszego, niż czarny', glitche itp.



Palety zaczynają się pod adresem PPU $3F00 oraz $3F10. By ustawić te adresy PPU używa portu $2006. Port musi być zapisywany "na raty" - dwukrotnie najpierw wyższy, później niższy bajt.

  LDA $2002    ; wczytaj status PPU by zresetować przerzutnik stanów wysoki / niski na wysoki
  LDA #$3F
  STA $2006    ; wpisz wysoki Bajt $3F10 w tamten adres
  LDA #$10
  STA $2006    ; wpisz niski Bajt $3F10 w tamten adres

Powyższy kod nakazuje PPU ustawić się w adresie $3F10. Teraz port danych PPU pod $2007 jest gotów do odbierania danych. Pierwszy zapis trafi do adresu, który ustawiliśmy ($3F10) a kolejne będą zwiększane już przez PPU automatycznie ($3F11, $3F12, $3F13) po każdym wczytaniu lub zapisaniu. Możesz dalej wprowadzać dane, a adresy będą wzrastać. Poniżej: jak ustawić pierwsze czery kolory w palecie:

  LDA #$32   ;kod dla jasnego niebieskawego
  STA $2007  ;wpisz do PPU $3F10
  LDA #$14   ;kod dla różowego
  STA $2007  ;wpisz do PPU $3F11
  LDA #$2A   ;kod dla zielonego
  STA $2007  ;wpisz do PPU $3F12
  LDA #$16   ;kod dla czerwonego
  STA $2007  ;wpisz do PPU $3F13

Możesz w ten sposób wypełnić resztę palety. Ale na szczęście jest szybsza metoda. Najpierw możesz użyć dyrektywy .db do przechowania danych:
PaletteData:

  .db $0F,$31,$32,$33,$0F,$35,$36,$37,$0F,$39,$3A,$3B,$0F,$3D,$3E,$0F  ;dane do palety tła
  .db $0F,$1C,$15,$14,$0F,$02,$38,$3C,$0F,$1C,$15,$14,$0F,$02,$38,$3C  ;dane do palety sprite'ów

Potem używa się pętli, żeby skopiować te bajty do palety w PPU. Rejestr X jest używany jako indels do palety i zliczania ile razy pętla już się powtórzyła. Chcesz skopiować na raz obie palety, łącznie 32 bajty. Indeksując standardowo od zera byłyby to wartości 0-31, ale na następnym pętla ma się zakończyć, więc będą to wartości od 0 do 32 (łącznie 33).

   LDX #$00                      ; zaczynamy od 0
LoadPalettesLoop:
   LDA PaletteData, x          ; wczytaj dane spod adresu (PaletteData + wartość x)
                                       ; 1. raz w pętli załaduje PaletteData+0
                                       ; 2. raz w pętli załaduje PaletteData+1
                                       ; 3. raz w pętli załaduje PaletteData+2
                                       ; i tak dalej
   STA $2007                     ; wpisz do PPU
   INX                               ; X = X + 1
   CPX #$20                      ; Porównaj X do hexa $20, dziesiętnie 32
   BNE LoadPalettesLoop     ; Odgałąź (z powrotem) do LoadPalettesLoop jeśli porównanie jest różne od zera
                                       ; jeśli porównanie było równe 32, kontynuuj kod poniżej

Kiedy ten fragment kodu się wykona i przeleci już cała pętla, mamy gotową paletę kolorów. Jeden bajt, albo też i całość palety można zmieniać podczas trwania programu.
Sprite'y
Wszystko co się porusza osobno od tła jest stworzone ze sprite'ów. Sprite to tile złożony 8x8 pikseli, który PPU może wrzycić w dowolnym miejscu na ekranie. Zazwyczaj obiekty składają się z kilku sprite'ów obok siebie. Przykładowo duży Mario albo Bowser. PPU starcza wewnętrznej pamięci na 64 sprite'y. To osobna pamięć, oddzielna od całej pozostałej pamięci wideo i nie może być rozszerzona.
DMA Sprite'ów
Najszybszą i najłatwiejszą metodą na przeniesienie twoich sprite'ów do pamięci sprite'ów jest DMA(ang. direct memory access). Oznacza to skopiowanie bloku RAMu z CPU do pamięci sprite'ów PPU. Do tego celu zazwyczaj używa się pamięci RAM z płyty głównej $0200-02FF. By rozpocząć transfer muszą zostać wpisane dwa bajty do portów PPU:

  LDA #$00
  STA $2003  ; ustaw niski bajt (00) adresu RAM
  LDA #$02
  STA $4014  ; ustaw wysoki bajt (02) adresu RAM, rozpocznij transfer.

W momencie drugiego zapisu DMA rozpoczyna się automatycznie. Zostaną skopiowane dane wszystkich 64 sprite'ów. Tak jak wszystkie aktualizacje grafiki, tę operację też trzeba wykonać podczas VBlank'a, dlatego też trafi on do sekcji kodu NMI.


Dane Sprite'ów
sprite potrzebuje 4 bajtów danych na swoją pozycję i informację o tile'u w tej kolejności:
1 - Miejsce Y - pionowa pozycja sprite'a na ekranie. $00 to szczyt ekranu. Cokolwiek ponad $EF ($F0, $F1...) jest poza dolną granicą ekranu.

2 - numer tile'a - numer (0 - 255) grafiki, która ma być wzięta z Pattern Table (Tabeli Szablonów)

3 - Atrybuty - bajt przedstawia kolor i informację o wyświetlaniu:
  7 6 5 432 1 0
  | | |         | |
  | | |        + +--- Paleta kolorów dla sprite'a. Wybierz zestaw czterech spośród 16 kolorów.
  | | |
  | | +------------- Priorytet (0: przed tłem; 1: za tłem)
  | +--------------- obróć sprite'a poziomo
  +----------------- obróć sprite'a pionowo

4 - Miejsce X - pozioma pozycja sprite'a na ekranie. $00 jest z lewej, cokolwiek ponad $F9 jest poza ekranem.

Te 4 bajty są powtarzane 64 razy (po jednym zestawie na jednego sprite'a) by wypełnić 256 bajtów pamięci dla sprite'ów. Jeśli chcesz edytować sprite'a 0, możesz zmienić bajty $0200-0203. Sprite 1 to $0204-0207, sprite 2 to $0208-020B, itd.


Włączanie NMI/Sprite'ów
Port PPU $2001 jest znów używany do włączania sprite'ów. Ustawiając bit 4 na 1 sprawimy, że się pojawią. NMI też musi być włączone, więc DMA Sprite'ów będzie odpalone i sprite'y będą kopiowane co każdą klatkę. Dzieje się to w porcie $2000 PPU. Pattern Table 0 też jest zaznaczone do wybierania sprite'ów z niego. Tło będzie pochodziło z Pattern Table 1 kiedy dodamy je później.

  PPUCTRL ($2000)
  76543210
  | ||||||
  | ||||++- Adresy nametable'i
  | ||||      (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)
  | |||+--- zwiększanie adresu VRAM co wczytanie/zapis PPUDATA przez CPU
  | |||       (0: zwiększ o 1, patterny będą wypisywane jeden po drugim w liniach poziomych)
  | |||       (1: zwiększ o 32, wypisywane "jeden pod drugim", czyli z góry na dół.)
  | ||+---- adres pattern table(tabeli szablonów) Sprite'ów 8x8 (0: $0000; 1: $1000)
  | |+----- adres pattern table Tła (0: $0000; 1: $1000)
  | +------ rozmiar Sprite'a(0: 8x8; 1: 8x16)
  |
  +-------- Wygeneruj NMI na początku
               vblank'a (0: off; 1: on)

Dodajmy trochę kodu, żeby ustawić sprite'a:
  LDA #$80
  STA $0200        ;ustaw sprite 0 w środku ($80) ekranu pionowo
  STA $0203        ;ustaw sprite 0 w środku ($80) ekranu poziomo.
  LDA #$00
  STA $0201        ;numer tile'a = 0
  STA $0202        ;paleta kolorów = 0, bez obracania

  LDA #%10000000   ; włącz NMI, sprite'y z Pattern Table(Tabeli Szablonów) 0
  STA $2000

  LDA #%00010000   ; bez podkreśleń kolorów (tło czarne), włączone sprite'y
  STA $2001


Podsumowując
http://www.nespowerpak.com/nesasm/sprites.zip
Pobierz i rozpakuj sprites.zip. Cały powyższy kod jest w pliku sprites.asm. Upewnij się, że sprites.asm, mario.chr i sprites.bat są w tym samym folderze co NESASM3, potem dwuklik w sprites.bat. Uruchomi to NESASM3 i powinno utworzyć sprites.nes. Otwórz .nes w FCEUXD SP żeby zobaczyć swoje dzieło! Tile o numerze 0 jest za głową i czapką Mario, widzisz? Edytuj -sprites.asm by zmienić położenie sprite'a (0 - 255), albo zmienić paletę kolorów (0 - 3).

Literatura uzupełniająca:
Oryginał [ENG]:
http://www.nintendoage.com/forum/messageview.cfm?catid=22&threadid=6082