* Graphic designers used a special sheets to draw the arts :

* There are two kinds of graphic on the screen : 1) Background 2) Sprites
* Anything that moves on the screen is a sprite (for example Mario), other fixed graphics are background
* Background and sprites are made from small tiles
* NES screen resolution is 256x240 pixel. In PAL systems the whole screen is visible but in NTSC systems only 256x224 pixel is visible. More info : Overscan
* Each tile is 8x8 pixel, so the full background is made from 32x30 tiles (256x240 pixel) :
* NES uses a very complex method to compress and store graphic data, why? Maybe because memory was expensive back then
* As you can see some of the tiles on the background picture is similar to each other, so the tiles can be reused.
* Tiles are stored inside of CHR (an EPROM memory inside of the cartridge)
* To see and edit those tiles you can use YY-CHR.NET or Tile Layer Pro :
* Need more info? then read this : PPU pattern tables
* Background and Sprites needs color, right? But you know NES hardware is not very powerful, it can only produce maximum of 64 different colors! Also it is not possible to use all of those 64 colors at the same time!
* You can choose and apply only 13 colors to background, and 12 other colors for sprites.
* Fortunately with some programming methods you can overcome these limitations, well to some extent! For example you can choose different colors for each stage of the game!
* For more info about colors read this : PPU palettes
* Yeah I know, NES has a lot of limitations, it is really disappointing, then again if you are a NES enthusiast then you have to live with its limitations
/////////////////////////////////////////////////////////////////////////////////////////////////
* To design a backgroud we can use GIMP but for learning propose we can skip this step and extract a background picture from other games.
Extracting graphic data from a NES game :
* Run Super Mario Bros. (W) [!].nes with FCEUX emulator
* Start the game and then press Pause on the keyboard
* Go to Debug > PPU Viewer. On the left you can see the tiles for sprites, on the right there are tiles of background
* There are some colors on the button. The first row is the colors of background. The second row is the colors of sprites.
* Go to Debug > Name Table Viewer. You can see the background picture here.
* Go to Debug > Hex Editor > View > PPU Memory
* Do not confuse PPU memory address with CPU memory address, they are completely separated from each other
* PPU has its own address space starting from $0000 to $3FFF
* From $0000 to $0FFF (4KB) is data of Left pattern table (sprites tiles)
* From $1000 to $1FFF (4KB) is data of right pattern table (background tiles)
* From $2000 to $2400 (1KB) is data of first name table (background graphic)
* From $3F00 to $3F0F (16bytes) is data of background colors
* From $3F10 to $3F1F (16Bytes) is data of sprites colors
* Copy those values and by using HxD save them separately : mario_spt.chr, mario_bg.chr, mario_bg.nam, mario_bg.pal, mario_spt.pal
/////////////////////////////////////////////////////////////////////////////////////////////////
Editing a background :
* You can edit the exiting backgrounds
* Download 8name which is a background editor
* Make a new text file and write this inside of it :
Code: Select all
name mario_bg* Make sure these files are in the same folder :
Code: Select all
name.exe
Bg_Editor.bat
alleg42.dll
mario_bg.nam
mario_bg.pal
mario_bg.chr
* After editing use ctrl + s to save the name table, then reassemble the game to see the output
/////////////////////////////////////////////////////////////////////////////////////////////////
NES Screen Tool :
* You can edit your extracted graphic files with NES Screen Tool
* Use "Patterns > Open CHR" to load "mario_bg.chr"
* Use "Nametable > Open nametable or map" to load "mario_bg.nam"
* Use "Palettes > Open palettes" to load "mario_bg.pal"
* After editing use "All > Save" to save the files
/////////////////////////////////////////////////////////////////////////////////////////////////
* Now we have all the necessary graphics to make a nes file :
- mario_bg.chr and mario_spt.chr --> 8x8 tiles
- mario_bg.nam --> Background picture generated by using tiles
- mario_bg.pal, mario_spt.pal --> Chosen Colors applied to the background and sprites
* We have to pay attention that tiles are stored inside of CHR ROM, while background picture and its color is actually inside of PRG ROM! In another word background picture is generated while playing the game, also colors applied to it at the same time. Codes inside of PRG writes the tiles value to the PPU memory to make the background (name table), also the same thing happens to the colors! It is damn confusing and difficult to understand at the beginning.
The following code generates a fixed background :
Code: Select all
;NES Programming Tutorial
;Level 5 : Background
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;Constants
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;Variables
.enum $0000
L_byte .dsb 1
H_byte .dsb 1
.ende
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;iNES header data (16bytes)
;32KB PRG + 8KB CHR + NROM-256 + Vertical Mirroring
.db $4E,$45,$53,$1A,$02,$01,$01,$00
.db $00,$00,$00,$00,$00,$00,$00,$00
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;PRG Bank0 $8000 ~ $BFFF (16KB)
.base $8000
RESET:
SEI
CLD
LDX #$FF
TXS
;Turn off NMI and rendering
LDA #%00000000
STA $2000
LDA #%00000000
STA $2001
;PPU warm up
LDA $2002
vBlank_wait1:
BIT $2002
BPL vBlank_wait1
vBlank_wait2:
BIT $2002
BPL vBlank_wait2
;Clear RAM
LDA #$00
LDX #$00
clear_loop:
STA $0000, X
STA $0100, X
STA $0200, X
STA $0300, X
STA $0400, X
STA $0500, X
STA $0600, X
STA $0700, X
INX
CPX #$00
BNE clear_loop
;Name table + Attribute
LDA $2002
LDA #$20
STA $2006
LDA #$00
STA $2006
LDA #<bg_nam
STA L_byte
LDA #>bg_nam
STA H_byte
LDX #$00
LDY #$00
nam_loop:
LDA (L_byte), Y
STA $2007
INY
CPY #$00
BNE nam_loop
INC H_byte
INX
CPX #$04
BNE nam_loop
;Background color setup
LDA $2002
LDA #$3F
STA $2006
LDA #$00
STA $2006
LDX #$00
bg_pal_loop:
LDA bg_pal, X
STA $2007
INX
CPX #$10
BNE bg_pal_loop
;Reset Scroll
LDA #$00
STA $2005
LDA #$00
STA $2005
;Turn on NMI and rendering
LDA #%00001000
STA $2000
LDA #%00001010
STA $2001
;Infinite loop
Forever:
JMP Forever
;---------------------------;
NMI:
RTI
;---------------------------;
IRQ:
RTI
;---------------------------;
.pad $C000,$FF
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;PRG Bank1 $C000 ~ $FFFF (16KB)
.base $C000
bg_nam:
.incbin "mario_bg.nam"
bg_pal:
.incbin "mario_bg.pal"
;---------------------------;
;Vectors
.org $FFFA, $FF
.dw NMI
.dw RESET
.dw IRQ
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;CHR Bank0 $0000 ~ $1FFF (8KB)
.base $0000
.incbin "mario_bg.chr"
.pad $2000,$AA
Explanation :
Code: Select all
.enum $0000
L_byte .dsb 1
H_byte .dsb 1
.endeCode: Select all
LDA #%00001010
STA $2001* To make graphic on screen you have to write graphic data to PPU memory
* But you can't write directly to PPU memory, you have to use PPU ports : $2006 and $2007
* By using $2006 you declare the address of PPU memory then by using $2007 you write the desired value to that address
* PPU Memory addresses are 16bit starting from $0000 ~ $3FFF (4KB)
Code: Select all
LDA #$20
STA $2006
LDA #$00
STA $2006* Each time you write a value to $2007, the PPU address is automatically adjusted to the next address, so you don't need to declare the PPU address with $2006 for sequential PPU memory addresses
Code: Select all
bg_nam:
.incbin "mario_bg.nam"Code: Select all
LDA #<bg_nam* We assigned L_byte to $00 already
Code: Select all
STA L_byteCode: Select all
LDA #>bg_nam
STA H_byte* From $0000 to $00FF is ram right? but it is kind of special, because we can show those address with this : $00 to $FF, we call those address Zero Page
* LDA (L_byte), Y : Let's imagine : $0000 = #$00 / $0001 = #$90 / Y = #$44. Then : $9000 is made. Then $9000 + $44 = $9044. Then the value inside of $9044 is loaded into A
* INY stands for INcrement Y, For example if the value of Y is #$44 then it will be #$45
* CPY stands for ComPare Y register. It compares the value of X with its following value
* INC H_byte, increase the value inside of $01 by one
* The codes of ";Name table + Attribute" actually transfers a total of 1KB (= 400 bytes in hex) data of background to PPU memory ($2000 ~ $2400)
* The codes of ";Background color setup" actually transfers a total of 16 bytes (= 10 bytes in hex) data of background color to PPU memory ($3F00 ~ $3F0F)
* $2005 is another PPU port which is used to move the background
* Need more info about PPU ports? then read this : PPU registers
* Need to learn about 6502 opcodes? then read this : Assembly In One Step
* Need a reference for assembly 6502 opcodes? then check this : NMOS 6502 Opcodes
/////////////////////////////////////////////////////////////////////////////////////////////////
Exercise :
Extract graphic data from other games and use them instead of mario_bg.nam, mario_bg.pal, mario_bg.chr.
/////////////////////////////////////////////////////////////////////////////////////////////////
Files :
asm6.exe
Assembler.bat
Game.asm
name.exe
Bg_Editor.bat
alleg42.dll
mario_bg.nam
mario_bg.pal
mario_bg.chr
/////////////////////////////////////////////////////////////////////////////////////////////////
Former Level : NES Programming Tutorial : Init Code
Next Level : NES Programming Tutorial : Move Background