Saturday, September 17, 2016

NESDev - Color Palettes

Since my last post, I have added a few more resources to my bibliography (which will be a separate post at the end of the project).  I recently received the book "I am Error" by Nathan Altice in the mail, and it so far has been a fantastic read.  It dives into the hardware or the NES and Famicom systems pretty early on, so I will probably reference the book a bit more in future posts.

I will also be cross-referencing a lot of terms and concepts from the "Nerdy Nights" tutorials with info from the NesDev Wiki.  As these tutorials are meant to sort of get you programming fairly quickly, they gloss over a lot of the details as to the inner workings of the hardware.  Hopefully my posts will be able to help make a bridge between the code samples and the interactions with the processors and memory.

Now then...

Color Palettes

  • There are essentially 2 groupings of color palettes, one for the background and one for sprites.
    • These 2 groupings each contain 8 separate color palettes (4 bytes in size).  Although each palette is 4 bytes in size, only 3 different colors could be stored in each palette, as you will see in the table below.
    • The PPU addresses start at $3F00 (background) and $3F10 (sprites).  The table of these values are listed below.  Note that some addresses (like $3F04, $3F09, etc.) are skipped.  These addresses contain either a) the common background color, shared in each background palette or b) transparency, used for sprites in each sprite palette
Courtesy of wiki.nesdev.com

  • The NES PPU had a total of 64 colors you could choose from, but was limited to only displaying 25 different colors on the screen at any one time.
    • This 25 color limit is broken up "4 palettes x 3 colors = 12 for sprites, 4 palettes x 3 colors = 12 for background tiles, 1 for background" (thanks Noel Berry).
Moving over to the programming...


Courtesy of Nerdy Nights - Week 4.  Each hex value represents one of the usable 64 colors in the PPU.

  • When writing colors into the background/sprite palettes, the appropriate address must be set into the PPU address $2006.  For example, passing $3F00 to $2006 would allow you to add colors to the background palette.  Each port must be written into $2006 twice, writing the high byte first, then for the low byte.  This can best be demonstrated by the Nerdy Nights code snippet below.

LDA $2002 ; read PPU status to reset the high/low latch to high
LDA #$3F
STA $2006 ; write the high byte of $3F10 address
LDA #$10
STA $2006 ; write the low byte of $3F10 address

In this case, the tutorial will be setting the color palette for sprites ($3F10).

  • AT this point, the PPU is set to start taking color values for its sprite palette.  As pointed out in the tutorial, you can load them one by one into $2007, where the PPU will automatically increment the palette address after each write to $2007.

  LDA #$32   ;code for light blueish
  STA $2007  ;write to PPU $3F10
  LDA #$14   ;code for pinkish
  STA $2007  ;write to PPU $3F11
  LDA #$2A   ;code for greenish
  STA $2007  ;write to PPU $3F12
  LDA #$16   ;code for redish
  STA $2007  ;write to PPU $3F13

Thankfully, "bunnyboy" points out that a much easier way to go about this is to create a ".db directive"...


PaletteData:
  .db $0F,$31,$32,$33,$0F,$35,$36,$37,$0F,$39,$3A,$3B,$0F,$3D,$3E,$0F  ;background palette data
  .db $0F,$1C,$15,$14,$0F,$02,$38,$3C,$0F,$1C,$15,$14,$0F,$02,$38,$3C  ;sprite palette data

A .db directive essentially works like the arrays of modern day programming, storing a large group of values into one place.  This can be combined with the use of the X Index register, which allows the program to step through each byte of data individually.

  LDX #$00                ; start out at 0
LoadPalettesLoop:
  LDA PaletteData, x      ; load data from address (PaletteData + the value in x)
                          ; 1st time through loop it will load PaletteData+0
                          ; 2nd time through loop it will load PaletteData+1
                          ; 3rd time through loop it will load PaletteData+2
                          ; etc
  STA $2007               ; write to PPU
  INX                     ; X = X + 1
  CPX #$20                ; Compare X to hex $20, decimal 32
  BNE LoadPalettesLoop    ; Branch to LoadPalettesLoop if compare was Not Equal to zero
                          ; if compare was equal to 32, keep going down

Once the above code finishes its application, the color palette is set up and ready to go.

The next post will go into more detail about the second part of "Nerdy Nights - Week 4": Sprites.  Seeing as how much information was put into a single post for color palettes, I may save the Sprites post for a later day this week.

-JWest

No comments:

Post a Comment