Hello All,
I have a (hopefully) quick question about the color palette. Before I was
only using 4 colors and it worked out with my background fairly decent.
Now I've increased the color palette to 8. However, my background is
still only using the first 4 colors and I was wondering how do you get it
to "map" (or use) some of the other colors? Is this where attribute tables
come in??
Thanks.
pattern tables contain the lower 2 bits of the color index value of a tile and attribute table cotain the upper 2 bits. so the value of color index is 4bit long in all.it can address 16 colors in max. hopefully, this will help u.
JJ.Loki wrote:
pattern tables contain the lower 2 bits of the color index value of a tile and attribute table cotain the upper 2 bits. so the value of color index is 4bit long in all.it can address 16 colors in max. hopefully, this will help u.
Thanks. That helps some. I also read the NESTechFAQ by Chris Covell.
Quote:
The NES' background palette has 16 entries in it, with some mirroring going on. But a tile in the name table can't access all 16 colours at once; it can only be made up of 4 colours from the total palette of 16. This is just a limitation imposed by Nintendo. So, the attribute table comes in and describes which 4 of the 16 colours in the palette a certain tile will take. Because the attribute table is of such a small size (64 bytes), it only has a resolution of 2 tiles x 2 tiles. So, each 16x16 pixel area on the background has to share the same 4 colours.
I understand what he's saying here but I'm just not too sure about
how to implement it?
Thanks.
If you're using nametable 0, I believe the attribute tables start at $23C0. It's a little weird since it's divided into 2 bit areas. So every 2 bits at $23C0-$23FF represent the color selection for each 16x16 pixel background block.
Memblers wrote:
If you're using nametable 0, I believe the attribute tables start at $23C0. It's a little weird since it's divided into 2 bit areas. So every 2 bits at $23C0-$23FF represent the color selection for each 16x16 pixel background block.
So just fill the pal color (or palette index #???) to 23C0 like you would the
name table @ $2000???
lynxsolaris wrote:
So just fill the pal color (or palette index #???) to 23C0 like you would the
name table @ $2000???
Or is that way off? Apparently I can't just pass color palette numbers to
it because when I tried that ... nothing changed.
lynxsolaris wrote:
lynxsolaris wrote:
So just fill the pal color (or palette index #???) to 23C0 like you would the
name table @ $2000???
Or is that way off? Apparently I can't just pass color palette numbers to
it because when I tried that ... nothing changed.
Use a palette index (possible numbers are just 0 through 3). It's kind of a pain to work with. Normally I've kept a copy of the attribute table in the CPU's RAM, because you have to modify it 2 bits at a time, and reading $2006 is a waste of vblank time IMHO.
The attribute coordinates are maximum of 16 X and 15 Y.
To change the attrib block at 0,0 to palette set #1, you'd write (binary) %xxxxxx01 to $23C0 (where X means whatever bits were there before). And %xxxx01xx for coords 1,0, %xx01xxxx for 0,1, %01xxxxxx for 1,1. That's the pattern to follow.
I'd say you could look at or use the code I wrote that handles nametable and attribute updates together, but it's a really ineffecient and crappy old mess. But here it is anyways.
It's the first routine on there. The label "attribute_table" is in CPU RAM.
http://www.parodius.com/~memblers/nes/neslib.s
Memblers wrote:
To change the attrib block at 0,0 to palette set #1, you'd write (binary) %xxxxxx01 to $23C0 (where X means whatever bits were there before). And %xxxx01xx for coords 1,0, %xx01xxxx for 0,1, %01xxxxxx for 1,1. That's the pattern to follow.
Memblers .. thanks for your help. I've reviewed your source code. I have
to say I haven't done much with bit shifting yet. So I was a little bit
confused as to what you were doing with the ASL before the attribute_table
stuff. Also, where you said "X means whatever bits where there before".
What do you mean by that. In your code you have 1s but if I haven't set
anything before then would they just be 0s? I'm gonna keep going over
it and re-re-re-read the stuff about attribute tables. But those where the
questions that just stood out to me now.
lynxsolaris wrote:
Memblers wrote:
To change the attrib block at 0,0 to palette set #1, you'd write (binary) %xxxxxx01 to $23C0 (where X means whatever bits were there before). And %xxxx01xx for coords 1,0, %xx01xxxx for 0,1, %01xxxxxx for 1,1. That's the pattern to follow.
So I was a little bit
confused as to what you were doing with the ASL before the attribute_table
stuff. Also, where you said "X means whatever bits where there before".
What do you mean by that.
It's a read-modify-write. For example, to change the lower-right attribute in an byte, you have to read the attribute byte (from VRAM or from RAM), modify only the upper bits, and write it back.
tepples wrote:
It's a read-modify-write. For example, to change the lower-right attribute in an byte, you have to read the attribute byte (from VRAM or from RAM), modify only the upper bits, and write it back.
I think I see what youre saying here. Just not sure of
where to
do this at?
Yeah, working with the attribute tables is a bitch. And you will need to learn how to use the SHIFTs, the ANDs and the ORs, as you'll need to manipulate individual bits in a byte.
Working with the name tables is easy, since 1 byte = 1 tile. So, unless you're willing to set up the colors of an area of 4x4 tiles at a time, you'll have to learn how to work with bits. Some games actually do update a 4x4 tile area at a time, to avoid complexity.
But if you're looking into changing the color of a random block in the middle of the screen, you'll have to take the attribute byte for that location, change the respective bits and write back. But we don't like to waste VBlank time reading and modifying stuff, so we keep a copy of the attribute tables in RAM, where we do all the dirty work, and just copy from there to the atribute tables during VBlank.
As Memblers said, the first attribute table starts at $23C0. The byte at that location will define the palettes used by the tiles at positions 0, 1, 2, 3, 32, 33, 34, 35, 64, 65, 66, 67, 96, 97, 98 and 99. That's 16 tiles, a 4x4 square at the top left corner of the screen. The first 2 bits of the attribute byte define the palette used by tiles at positions 0, 1, 32 and 33. The next 2 bits are the palette index for tiles 2, 3, 34 and 35. And so on.
So, if you want to set the palette for tiles 0, 1, 32 and 33, youd just set the lower 2 bits of the attribute byte to the palette you want to use. Since you're learning, you could just try setting these 2 bits to whatever you want and set all others to 0, so you can see the results. If you KNOW exactly what you want to show, you can just hard code the values you write to the attribute table. The read-modify-write is for dynamic games, that draw their graphics based on 16x16 pixel blocks, mostly.
Since you're used to have all 0's in the attribute tables, try setting a few of the bits to point to adifferent palette and you'll soon understand how it works, by seeing the results on screen.
tokumaru wrote:
Yeah, working with the attribute tables is a bitch.
Yes, I agree 100%.
tokumaru wrote:
Since you're used to have all 0's in the attribute tables, try setting a few of the bits to point to adifferent palette and you'll soon understand how it works, by seeing the results on screen.
I really hate to ask this but could you give me a mini code example.
Memblers example, while I thank him for letting me see it, is a little bit too
advanced for me at this point. This is *kinda* what I've been messing with.
Code:
lda #$23
sta $2006
lda #$C0
sta $2006
lda #%xxxxxx01
sta $2007
Something like that, maybe????????????????????? I'm having a problem
*seeing* it from a syntax standpoint.
Thanks.
That code is correct, but make sure that the latch is set to the first write otherwise the VRAM address will be set to $C023, not $23C0.
WedNESday wrote:
That code is correct, but make sure that the latch is set to the first write otherwise the VRAM address will be set to $C023, not $23C0.
sorry but what do you mean by "latch"?
lynxsolaris wrote:
WedNESday wrote:
That code is correct, but make sure that the latch is set to the first write otherwise the VRAM address will be set to $C023, not $23C0.
sorry but what do you mean by "latch"?
The latch is a 1-bit PPU value that decides between a high and low byte write. If the latch is not set then the next write to $2006 will be to the upper byte (i.e. $xx00). If it is set then the next write will be to the lower byte (i.e. $00xx).
WedNESday wrote:
The latch is a 1-bit PPU value that decides between a high and low byte write. If the latch is not set then the next write to $2006 will be to the upper byte (i.e. $xx00). If it is set then the next write will be to the lower byte (i.e. $00xx).
Understand. What is the default for the latch?
EDIT: and when am I suppose to apply the above type code? Before I
write the nametable information or after?
lynxsolaris wrote:
WedNESday wrote:
The latch is a 1-bit PPU value that decides between a high and low byte write. If the latch is not set then the next write to $2006 will be to the upper byte (i.e. $xx00). If it is set then the next write will be to the lower byte (i.e. $00xx).
Understand. What is the default for the latch?
EDIT: and when am I suppose to apply the above type code? Before I
write the nametable information or after?
The default value of the latch is 0. when you write to either $2005/$2006 the latch is flipped. If you read from $2002 then the latch is reset.
Do not expect the latch to be 0 on startup. You must never assume the state of any unprepped memory unless you specifically set it first.
Always, always read $2002 at least once in your program before you perform any $2005 / $2006 writes. This will ensure the latch is clear (making your next write the "first" write)
Ok I must still be missing something.... Is there something else I'm suppose
to be doing before
Code:
lda #$23
sta $2006
lda #$C0
sta $2006
lda #%xxxxxx01
sta $2007
Because I don't have any color change. It's still using the first 4 colors
in my palette. I've tried changing #%xxxxxx01 to xx01xxxx but I didn't
see any change. I've loaded my nametable into $2000 and my
background palette colors into $3F00. I also am reading $2002 at the
beginning before any $2005/$2006 writes.
Ok guys I'm failing miserably .... I'm at the mercy of this board! Plllleeeaaasse help ... hating some attribute tables right now...
You don't actually use x's in the byte. For now just try the checkerboard method: write %01000001 in the whole attribute table and see how your screen changes.
tepples wrote:
You don't actually use x's in the byte. For now just try the checkerboard method: write %01000001 in the whole attribute table and see how your screen changes.
yeah I know not to use x's. I had been trying it with 0's like
#%00000001 etc. I did as you instructed but had no change. I'm doing
this write after I do my name table stuff. Could that be the problem?
Thanks!
here is what I have in its entirety ... well almost...
Code:
.inesprg 1
.ineschr 1
.inesmir 0
.inesmap 0
.zp
scrollPos = $00
.bss ; non-zero page memory allocation
; $700+ for RAM
; ==================================
; Memory Allocation
; =================================
... omitted for space ...
; ==================================
; Begin Code
; ==================================
.code
.org $8000
.bank 0
main:
sei
cld
lda #$00
sta <scrollPos
ldx #$ff
txs
inx
stx $2000
stx $2001
jsr wait_vblank
;jsr clr_spr
jsr wait_vblank
jsr clr_spr
jsr palette
jsr nametable
jsr inits
jsr ppuinit
end:
jmp end
wait_vblank:
bit $2002
bpl wait_vblank
rts
clr_spr:
lda #0
tay
clr2_spr:
sta $700,y
iny
bne clr2_spr
rts
; =================================
; Color Palette (Background & Sprites)
; =================================
palette:
lda #$3F
sta $2006
lda #$10
sta $2006
lda #$0d
sta $2007
lda #$08
sta $2007
lda #$28
sta $2007
lda #$19
sta $2007
lda #$3F
sta $2006
lda #$00
sta $2006
lda #$0D
sta $2007
lda #$30
sta $2007
lda #$22
sta $2007
lda #$16
sta $2007
lda #$0D
sta $2007
lda #$00
sta $2007
lda #$10
sta $2007
lda #$30
sta $2007
lda #$0D
sta $2007
lda #$00
sta $2007
lda #$16
sta $2007
lda #$30
sta $2007
lda #$0D
sta $2007
lda #$3C
sta $2007
lda #$1B
sta $2007
lda #$09
sta $2007
rts
; =======================
; Name table setup
; =======================
nametable:
lda #$20
sta $2006
lda #$80
sta $2006
ldy #64
lda #$04
ceiling:
sta $2007
dey
bne ceiling
lda #$23
sta $2006
ldx #$40
stx $2006 ; name table @ $2300
ldy #96
lda #$04
drawfloor:
sta $2007
dey
bne drawfloor
; attribute table ... WTF ....
lda #$23
sta $2006
lda #$C0
sta $2006
lda #%01000001
sta $2007
rts
; =======================
; Initialization of Sprite
; =======================
inits:
... omitted for space ...
rts
; ========================
; PPU Init
; ========================
ppuinit:
lda #%10001010 ;
sta $2000
lda #%00011010
sta $2001
rts
; =========================
; NMI Routine
; =========================
nmi:
lda #%10001000
sta $2000
lda scrollPos
ldx #$00
sta $2005
stx $2005
jsr controlStrobe ; read controller
jsr dmatrans
int:
rti
controlStrobe:
lda #$01
sta $4016
lda #$00
sta $4016
lda $4016 ; A button .. nothing for now
lda $4016 ; B button ...
lda $4016 ; Select
lda $4016 ; Start
lda $4016 ; Up
lda $4016 ; down
lda $4016 ; Left
and #1
beq Right_Press
dec scrollPos
Right_Press:
lda $4016 ; Right
and #1
beq stop_rts
inc scrollPos
stop_rts:
rts
dmatrans:
lda #7
sta $4014
rts
.bank 1
.org $fffa
.dw nmi,main,int
.bank 2
.org $0000
.incbin "img.chr"
Maybe this will help you see where my problem is ....
Thanks for everyones help!
Well, each attribute byte covers 4 colors for 4 group of tiles. Each 2 bit is a color.
At PPU $23c0 : %ddccbbaa
a = color of tiles $0, $1, $20, $21
b = color of tiles $2, $3, $22, $23
c = color of tiles $40, $41, $60, $61
d = color of tiles $42, $43, $62, $63
If you don't have too much experience with nametables, tiles are disposed as folowwing :
$0, $1, $2, $3, ...
$20, $21, $22, $23 ....
$40, $41, $42, $43 ....
Each row is $20 tiles wide.
Now, the 8 first attribute bytes (PPU $23c0-$23c7) controls overall colors for tiles $0-$7f (the first 4 rows of tiles), $23c8-$23cf controls the 4 following rows, etc...
The last 8 attribute bytes ($23f8-$23ff) controls color only for 2 rows instead of 4. The upper nybble (upper 4 bits) of theese byte is "dummy", because the nametable stops after $23c0.
Bregalad wrote:
Well, each attribute byte covers 4 colors for 4 group of tiles. Each 2 bit is a color.
At PPU $23c0 : %ddccbbaa
a = color of tiles $0, $1, $20, $21
b = color of tiles $2, $3, $22, $23
c = color of tiles $40, $41, $60, $61
d = color of tiles $42, $43, $62, $63
If you don't have too much experience with nametables, tiles are disposed as folowwing :
$0, $1, $2, $3, ...
$20, $21, $22, $23 ....
$40, $41, $42, $43 ....
Each row is $20 tiles wide.
Now, the 8 first attribute bytes (PPU $23c0-$23c7) controls overall colors for tiles $0-$7f (the first 4 rows of tiles), $23c8-$23cf controls the 4 following rows, etc...
The last 8 attribute bytes ($23f8-$23ff) controls color only for 2 rows instead of 4. The upper nybble (upper 4 bits) of theese byte is "dummy", because the nametable stops after $23c0.
OK!!! I think I'm starting to finally understand. The tile that I'm using
as my floor (which I'm trying to change the color of) is tile $4 and $5.
So that would be the reason the color isn't changing because because its
not in that first group of tiles (as you listed above a,b,c,d). So would this
be where bit shifting would come into play?
Thanks.
MUWAHAHAHAHAHAHAHA! It hit me in the face like being slapped by a
pissed ex-girlfriend! Thanks to everyone who explained it to me. I've got
it! In your face attribute tables. Definitely hardcore though.
lynxsolaris wrote:
...Definitely hardcore though.
Well not for us it wasn't. Explaining it to you though, was.
WedNESday wrote:
Well not for us it wasn't. Explaining it to you though, was.
Yeah well now its not a problem for me either.
WedNESday wrote:
Well not for us it wasn't. Explaining it to you though, was.
That type of attitude isn't appropriate for a newbie forum. If you'd like to help, by all means, contribute. If not, you should refrain from issuing discouraging remarks.
WedNESday wrote:
Well not for us it wasn't. Explaining it to you though, was.
Attributes are so easy, right WedNESday? I bet you never had any problems with them. *cough*
http://nesdev.com/bbs/viewtopic.php?t=824 *cough*