revision 1: use pal(#,#,1) commands instead of poke() commands to set colors on screen palette.
I spent a while being very, very confused about screen palettes and draw palettes, but I've started to feel like I've got a hang of it? And I decided to make a visual expression of how these work as a PICO-8 cart.
In the default state, the screen palette contains the sixteen colors of the default palette - 0-15 - and the draw palette links the sixteen draw colors 0-15 directly to these default colors.
When the draw palette changes, different colors from the screen palette are loaded into the draw color slots. The sprite still refers to the same draw colors - in this case, 0-3 across the top, 4-7 in the second row, 8-11 in the second-to-bottom row, and 12-15 in the bottom row - but these draw colors have been redefined in terms of the screen palette.
...and the screen palette in turn can be redefined by changing the colors in its 16 slots.
I think how this is intended to be understood is:
- 4 components: video output hardware (5-bit input, RGB output), screen palette RAM (4-bit address, 8-bit output), screen data RAM (14-bit address, 4-bit output), draw palette lookup table RAM (4-bit address, 4-bit output)
- Every sixtieth of a second, one frame of graphics is sent to the monitor. As the hardware scans through the 128x128 pixels of the screen data, the 4-bit screen data output addresses the screen palette RAM, and the high-order bit plus lower 4 bits of the screen palette output goes to the video output hardware. (I can attest from having bugs in my screen palette code for a while that the other bits in the screen palette are ignored.)
- When commands are run to draw graphics on the screen, the 4-bit addresses to be drawn go through the draw palette lookup table to set the 4 bits actually stored in the corresponding addresses of the screen data RAM.
Or, in less technical terms: the data stored for the sprite (or whatever) chooses a row in the draw palette (center) which chooses a row in the screen palette (left) which chooses a color on the screen. Changing the draw palette doesn't change what the screen shows until PICO-8 draws something new to the screen data; changing the screen palette does.
What honestly made it click for me, though, was thinking in practical terms.
The draw palette, for example, is a tool for recoloring images as I draw them. For example, if I have this little gray box stored as a sprite in my sprite sheet:
then I can use the draw palette to declare that I'm drawing it as an orange sprite instead:
The screen palette, on the other hand, I think of as 16 meanings. Rather than thinking of the, say, 11th color in the screen palette as a color, when I am using the screen palette to change the colors of images, I think of it by its purpose: in this case, the color of the character's shirt.
Then, changing that color represents a change corresponding to that meaning: to put the value 136 in screen palette slot 11, then, is to say that the color of the character's shirt is not green, it is red.
These ideas can obviously be combined - perhaps screen palette 1 is the color of player 1's vehicle and screen palette 2 is the color of player 2's vehicle, and which color is drawn when a vehicle sprite is drawn is selected using the draw palette. Thus, both players can select the colors of their vehicles and both vehicles can be drawn using the same sprites.
This is very long and probably well-known in the community, but I figured I'd make the tutorial anyway because I'm proud of figuring this out.
This is some work you've done, but it shouldn't be that difficult to understand, @packbat.
You have your basic 16-colors. To access the higher colors in your drawing routines, just add 128 to this command thus:
pal(n1,n2,1)
Where n1 the index you want to change is a number from 0 to 15.
And n2 the color to change it to. It is a number from 0 to 15 =OR= 128-143 for the extended.
Thus to change the bright blue #12 to a darker blue #140 using the extended set, the code is merely:
pal(12,140,1) |
To reset just this one color, assign it the same number:
pal(12,12,1) |
To reset every color in the palette use:
pal() |
Y'know, reading the Wiki page, I assumed that wouldn't work? I'll try that, though - that's easier than poking memory addresses.
That said, it wasn't really the technical aspect of the palettes that took me a little while to grok. Using pal(12,140,1) is easier than using poke(0x5f1b,140) - not only does it explain what it does, it's much more likely that I remembered the "pal" command correctly than the memory address for slot 12 of the screen palette - but what was confusing me was looking at the sprite sheet and thinking I was seeing colors filling each pixel and not numbers from 0-15 that the draw state translates to numbers from 0-15 that the screen palette translates to RGB.
If that makes sense.
Thank you for the suggestion! I'll try that.
That's right. I don't think of color #1 as "dark blue". I think of #1 as "unobtrusive background decoration color". So when I draw background decorations, I use color #1. Sure it "looks dark blue" in the sprite editor.. But in code, I can pal(1,x,1) where x is any color, really. Could be dark red on one level, green on another.
So the 'colors' of PICO-8 aren't colors for me -- they are palette indices. That I can change dynamically from code as suits me. And I can choose any 16 of the 32 to appear on screen at once; so, usually, I choose the colors on a per-level or per-screen basis.
I use the wonderful Palette Maker by 2darray to construct my colors:
https://www.lexaloffle.com/bbs/?tid=35462
[Please log in to post a comment]