Log In  

As stated in the title, you can now use up to 32 colors at the same time in pico-8 now.

The feature was revealed by Zep in this thread: https://www.lexaloffle.com/bbs/?tid=38555

This makes all the suggestions I gave in that thread possible and more.

You can't simply use all colors all over the screen though. You have 2 screen palettes and you basically have to select which palette you will use on each drawn line on the screen. In the gif above, the screen is divided into 2 halves, each with its own palette.

Palette Scanlines

Here is the code I used for both screen palettes:

--regular screen palette
8+(curr_shield==6 and 128 or 0),2,128+10,128+11,

--values 0x10 and 0x30 to 0x3f change the effect
--new colors on the affected line
--0x5f70 to 0x5f7f are the 16 sections of the screen
--0xff is the bitfield of which of the 16 line of the section are affected

The first pal() is to set the game's screen palette. Nothing new here.

poke(0x5f2c,0x40) enables the 2nd palette. This is the same address that changes screen modes (rotated, stretched, mirrored). You can add these effects as usual, so 0xc5 (0x40+133) will rotate the screen and enable the 2nd palette. See the wiki for all effects. This poke is no longer needed after update 0.2.1.

Pal([table],2) changes the secondary palette. The second parameter defines the target palette (0 for draw, 1 for display, 2 for secondary). You can change colors individually with pal(c1,c2,2) as usual too. You can also access it by peeking/poking addresses 0x5f60 to 0x5f6f.

The memset at the end is a bit more complicated: each address from 0x5f70 to 0x5f7f is a section of the screen. 0x5f70 is the first 8 lines, 0x5f71 is the next 8, etc, all the way to the bottom, 0x5f7f. The value you insert in the address is a bitfield for the 8 lines of that section. 0b1 will affect the first line, 0b11 will affect the first two lines, 0b1010101 will intercalate the lines between the two palettes, and 0b11111111 (or 0xff) will change all lines in the section.

With this, you can select either palette for all lines on the screen. But what if you want to use columns instead of horizontal lines? poke(0x5f2c,133) will rotate the screen, so if you rotate the sprites back to compensate for the screen rotation you can have something like this:

Each character has its own palette!

CRT effect, using the same principles! memset(0x5f70,0xaa,16) alternates lines!

In Moonrace I used the second palette for the mugshots! This might be the first game to use all 32 colors..? :)

Gradient Fill

If you poke(0x5f5f,n) with values between 0x30 and 0x3f, you'll have a different effect. The color corresponding to the last digit of the address will be swapped for a gradient of colors. Each of the 16 sections will be swapped for a different color (pokes 0x5f60 to 0x5f6f). An example will make it clearer:

Here the black background of the game was swapped for a gradient of the 16 basic colors, using the code below:

for i=0,15 do

So what does the 0x5f70 address do in this mode? Now each bit determines if that particular line will use the corresponding 0x5f6n color or 0x5f6n+1. Adding the code below will produce the following effect:


This might seem a bit unimpressive at first, but remember that you are free to use any of the 32 colors in this gradient, not only the ones you're using currently on the screen. This can be used to add colors to a platformer background or background effects in a shmup for instance. Here is a quick example:

If you look closely the game uses all 15 colors in the foreground and UI except for color #12 (light blue). The light blue is used for the gradient, using the regular colors 0, 1, 12, 6, and 7 and also 0x81 and 0x8c from the alternate palette (18 total colors). Here's another example using 21 colors:

Here is the code for this gradient. Just swap the colors for whatever you like :)

--swap 0x30 for 0x3n where n is the color that will be swapped for the gradient
--put the gradient colors in the table below:
--blend lines

You can use the gradient fill to add an extra color for some objects like in this example. Just be sure they never are on the same line. In this case, the camera never moves in the y axis, so there's no way they will overlap.

That's all I have for now. Have fun!

P#78518 2020-06-25 22:17 ( Edited 2021-11-23 13:16)


Thanks for the followup post! Great stuff as always.

P#78521 2020-06-25 22:40

Agreed. Thank you for taking the time to write this up, @BoneVolt! 🤓👍

P#78621 2020-06-28 16:28

If you want a reference to the whole 32-color palette within PICO-8 itself, here it is!

Cart #all_32_colors-0 | 2020-08-15 | Code ▽ | Embed ▽ | No License

EDIT: Here's the gradient mode showing 31 colors! Press the left and right arrows to select the color to be replaced with the gradient.

Cart #gradient_31_colors-0 | 2020-08-16 | Code ▽ | Embed ▽ | No License

P#80804 2020-08-15 02:26 ( Edited 2020-08-16 19:20)

I think I found something the gradient/color bar mode is useful for! Seizure'y skies! Sorry Zep if I basically leaked your Jelpi demo game!

Cart #jelpi_seizure_sky-0 | 2020-08-15 | Code ▽ | Embed ▽ | No License

Also, note that the +1 offset on gradient color 15 (which is on the last 8 rows of the screen) will actually wrap back to gradient color 0, found at address 0x5F60, not 0x5F70. It's only possible to get 31 (16 gradient + 15 unaffected) colors on-screen in this mode instead of a whole 32.

P#80824 2020-08-15 19:26 ( Edited 2021-07-26 22:46)

I added 2 new examples: The mugshots in Moonrace and the rabbit demo that uses the gradient fill to add more colors to many objects!

P#85855 2020-12-28 14:48

@carlc27843 just posted in the PICO-8 Discord server about a third high-color mode! I decided to make a cart that demonstrates it.

This requires 0x5F2C to be set to 1 to make the screen be the left 64x128 half stretched out horizontally. I think no other values seem to work. 0x5F5F must be set to 0x20. I don't know if 0x5F70 to 0x5F7F have effects in this mode.

When these pokes are done, a 5th bitplane is turned on by the means of pixels in the other 64x128 half of the screen buffer being non-zero. This will cause the corresponding pixels in the stretched-out left half to be using the secondary palette instead of the primary one, similar to what mode 0x10 does on a line-by-line basis.

Press any button to see this mode kick in!

Cart #fifth_bitplane_demo-0 | 2021-04-17 | Code ▽ | Embed ▽ | No License

P#90752 2021-04-17 23:12

Maaaaan! I know this thread is old, but it helped me soo much with my project!

I wanted a day/night cycle, which was no problem, but I wanted it to not effect the menu, when it opens. Now that I understood how all this memset thing worked within the 2 palettes, thanks to the great explanation here, I could manage it.

Thank you very much, @BoneVolt

P#146315 2024-04-10 19:12

[Please log in to post a comment]