Difference between revisions of "Palettes"

From SpecNext official Wiki
Jump to: navigation, search
(Removing Sol's lovely corrected image, but we don't need two.)
 
(7 intermediate revisions by 2 users not shown)
Line 1: Line 1:
To increase the number of available colours on screen, the Spectrum Next supports palletized colours.
+
== Palettes and Colour Mapping ==
  
Colour IDs in [[Layer 2]], [[Tilemap]] and [[Sprites]] are always taken as palette indices. Colour values in the ULA are mapped to the palette as fixed indices, or can be taken as partial palette indices if Enhanced ULA mode is enabled. The palette entry numbers for standard ULA mode are: 0-7 for the standard ink colors, 8-15 for BRIGHT ink colors, 16-23 for standard paper and border colors, and 24-31 for BRIGHT paper colors.
+
To increase the number of available colours on screen, the Spectrum Next supports '''palletized colours'''. The number of displayable colours varies depending on the graphics mode:
  
With Enhanced ULA mode enabled, the {{NextRegNo|$42}} defines how particular ULA attribute breaks into INK and PAPER color. The INK colors are mapped from index 0 in palette, PAPER (and BORDER) colors are mapped from index 128, except when in "full ink" mode (ink mask = 255), then PAPER and BORDER color is taken from {{NextRegNo|$4A}}.
+
* '''ULA''' – 15 colours on screen at once (7 with optional BRIGHT - as bright black is still black), using 1 of 2 ULA palettes
 +
* '''ULANext''' – Up to 256 colours via attribute mapping, using 1 of 2 ULA Next palettes
 +
* '''Sprites''' – 16 colours per sprite (4-bit) with palette offsets or 256 colours (8-bit), using 1 of 2 sprite palettes
 +
* '''Layer 2''' – Full 256-colour display, using 8-bit pixel values as palette indices, using 1 of 2 Layer2 palettes
 +
* '''Tilemap''' – One of two tilemap palettes used for final colour lookup.
  
Palette configuration can be done through registers $40-$44 and $6B. {{NextRegNo|$43}} sets which palette is being set up. There are two palettes each for Layer 2, Sprites, Tilemap and ULA; which one of the two is used for each is selected using the lower bits of {{NextRegNo|$43}} and in {{NextRegNo|$6B}}.
+
Colour IDs in [[Layer 2]], [[Sprites]], and the [[ULA]] are treated as '''palette indices'''. These indices point to colours defined in the palette memory.
  
Once a palette is selected, {{NextRegNo|$40}} sets the palette entry number to set up; you can then send the color to set it to on {{NextRegNo|$41}} ''or'' {{NextRegNo|$44}} which then auto-increment. $41 is used for sending 8-bit colours in RRRGGGBB format; the "missing" third blue bit is set to an OR between the other two. $44 is used for sending 9-bit colours in two byte packets; the first byte sent should be RRRGGGBB as with $41, and the second byte's LSB fills in the third blue bit. For Layer 2 color the top bit in second byte signals "priority" colour, which makes particular Layer 2 pixel to be drawn on top of everything else, overriding current order of layers.
+
== Setting Palette Colours ==
  
 +
To define a colour in a palette:
  
[[File:256-palette.png|left|thumb| Default 256 colour 8-bit indexed palette.]]
+
# Use {{NextRegNo|$43}} to select which palette to write to 
 +
# Use {{NextRegNo|$40}} to select the '''palette entry index''' 
 +
# Then send the colour using:
 +
## {{NextRegNo|$41}} to send an '''8-bit colour''' in '''RRRGGGBB''' format 
 +
## ''or'' {{NextRegNo|$44}} to send a '''9-bit colour''', as two bytes:
 +
### First byte: RRRGGGBB 
 +
### Second byte: 
 +
###* bit 0 = the '''third blue bit''' 
 +
###* For Layer 2: bit 7 = '''priority colour''' — forces the pixel to draw above all layers
 +
 
 +
{{NextRegNo|$41}} generates the missing third blue bit automatically as an OR of the other two. 
 +
Both registers {{NextRegNo|$41}} and {{NextRegNo|$44}} will auto-increment the palette index if auto-increment is enabled in {{NextRegNo|$43}}.
 +
 
 +
== ULA and ULANext Colour Mapping ==
 +
 
 +
For the ULA, colour mapping behaves differently depending on the mode:
 +
 
 +
* '''Standard ULA'''
 +
** INK: palette indices 0–7
 +
** BRIGHT INK: indices 8–15
 +
** PAPER and BORDER: indices 16–23 and 24–31
 +
 
 +
* '''ULANext mode''' (enabled via bit 0 of {{NextRegNo|$43}}):
 +
** INK: indices 0–127 
 +
** PAPER/BORDER: indices 128–255 
 +
** Mask in {{NextRegNo|$42}} defines how attribute byte is split into INK and PAPER 
 +
** If mask is 255 (full ink), PAPER and BORDER colour come from fallback in {{NextRegNo|$4A}}
 +
 
 +
ULA+ is also avilable by enabling bit 3 of {{NextRegNo|$68}} with further information on how ULA+ works here : https://zxdesign.itch.io/ulaplus
 +
 
 +
== Palette Registers in Detail ==
 +
 
 +
=== {{NextRegNo|$40}} – Palette Index ===
 +
* Selects the palette index to modify 
 +
* This index will apply to whichever palette is selected via {{NextRegNo|$43}} 
 +
* Auto-increments after a write, if enabled 
 +
* ULA-specific behaviour:
 +
** Standard INK = indices 0–7
 +
** Bright INK = 8–15
 +
** PAPER = 16–23
 +
** Bright PAPER = 24–31 
 +
** In ULANext, INK uses a subset of 0–127 and PAPER uses 128–255
 +
** In ULA+ mode, the top 64 entries hold the ULA+ palette.
 +
** The ULA always takes border colour from paper for standard ULA and ULAnext.
 +
 
 +
=== {{NextRegNo|$41}} – 8-bit Colour Value ===
 +
* Writes an 8-bit colour value in '''RRRGGGBB''' format 
 +
* The missing third blue bit is generated via OR of the two blue bits 
 +
* Writing updates the current palette entry and increments the index (if auto-increment is enabled) 
 +
* Reads do not auto-increment and only return the last 8-bit value
 +
 
 +
=== {{NextRegNo|$42}} – ULANext Attribute Format ===
 +
* Defines how many bits of the ULA attribute byte represent INK (rest is PAPER) 
 +
* Must be one of: 1, 3, 7, 15, 31, 63, 127, 255 
 +
* INK index = base 0 
 +
* PAPER + BORDER index = base 128 
 +
* If not a valid mask, INK = attribute AND mask, and PAPER/BORDER use fallback from {{NextRegNo|$4A}}
 +
* The 255 value enables the full ink colour mode making all the palette entries INK. In this case PAPER and border are both taken from the fallback colour in nextreg 0x4A.
 +
* If the mask is not one of those listed above, the INK is taken as the logical AND of the mask with the attribute byte and the PAPER and border colour are again both taken from the fallback colour in {{NextRegNo|0x4A}}.
 +
 
 +
=== {{NextRegNo|$43}} – Palette Control ===
 +
* bit 7 = Disable auto-increment 
 +
* bits 6–4 = Select palette to write or read:
 +
** <code>000</code> = ULA 1st 
 +
** <code>100</code> = ULA 2nd 
 +
** <code>001</code> = Layer 2 1st 
 +
** <code>101</code> = Layer 2 2nd 
 +
** <code>010</code> = Sprites 1st 
 +
** <code>110</code> = Sprites 2nd 
 +
** <code>011</code> = Tilemap 1st 
 +
** <code>111</code> = Tilemap 2nd 
 +
* bit 3 = Use Sprites palette (0 = first palette, 1 = second palette) (soft reset = 0)
 +
* bit 2 = Use Layer 2 palette (0 = first palette, 1 = second palette) (soft reset = 0)
 +
* bit 1 = Use ULA palette (0 = first palette, 1 = second palette) (soft reset = 0)
 +
* bit 0 = Enable ULANext mode
 +
 
 +
=== {{NextRegNo|$44}} – 9-bit Colour Value ===
 +
* Two consecutive writes are needed:
 +
** First byte: '''RRRGGGBB''' 
 +
** Second byte:  '''P000000B'''
 +
*** bit 0 = third blue bit 
 +
*** For Layer 2: bit 7 = '''priority colour''' (Layer 2 pixel is drawn above all other layers). If you need the same colour in both priority and normal modes, you will need to have two different entries with the same colour one with and one without priority.
 +
* Auto-increments index if bit 7 is 0 in {{NextRegNo|$43}}
 +
* Reads only return second byte - does not increment.
 +
* Writing to {{NextRegNo|$40}}, {{NextRegNo|$41}}, or {{NextRegNo|$43}} resets to first write
 +
 
 +
=== {{NextRegNo|$4A}} – Fallback Colour ===
 +
* 8-bit colour used if all layers are transparent 
 +
* Also used as PAPER/BORDER when ULANext attribute mask is invalid or set to 255 (soft reset = 0xe3)
 +
 
 +
=== {{NextRegNo|$4B}} – Sprite Transparency Index ===
 +
* Sets which palette index will be treated as transparent in sprite rendering (soft reset = 0xe3)
 +
* Only bottom 4 bits are used for 4-bit sprites
 +
 
 +
=== {{NextRegNo|$4C}} – Tilemap Transparency Index ===
 +
* Lower 4 bits set the tilemap transparent colour index (soft reset = 0xf)
 +
* Upper 4 bits must be zero
 +
 
 +
== Prepared Palette Files ==
 +
 
 +
The following palettes were created by '''Stefan Bylund''' for various graphics software:
 +
 
 +
{| class="wikitable"
 +
! Tool / Format !! 256 Colour Palette !! 512 Colour Palette
 +
|-
 +
| Photoshop || [https://github.com/stefanbylund/zxnext_bmp_tools/tree/master/palettes/zxnext-palette-256.act .act] || –
 +
|-
 +
| GIMP || [https://github.com/stefanbylund/zxnext_bmp_tools/tree/master/palettes/zxnext-palette-256.gpl .gpl] || [https://github.com/stefanbylund/zxnext_bmp_tools/tree/master/palettes/zxnext-palette-512.gpl .gpl]
 +
|-
 +
| JASC-PAL || [https://github.com/stefanbylund/zxnext_bmp_tools/tree/master/palettes/zxnext-palette-256.pal .pal] || [https://github.com/stefanbylund/zxnext_bmp_tools/tree/master/palettes/zxnext-palette-512.pal .pal]
 +
|-
 +
| Paint.NET || [https://github.com/stefanbylund/zxnext_bmp_tools/tree/master/palettes/zxnext-palette-256.txt .txt] || [https://github.com/stefanbylund/zxnext_bmp_tools/tree/master/palettes/zxnext-palette-512.txt .txt]
 +
|}
 +
 
 +
<small>Only 256 colours can be displayed at once, even when using 512-colour palettes.</small>
 +
 
 +
More tools and files by Stefan can be found here : 
 +
[https://github.com/stefanbylund/zxnext_bmp_tools github.com/stefanbylund/zxnext_bmp_tools]
 +
 
 +
== Palette Visuals ==
 +
 
 +
[[File:256-palette-2.png|left|thumb|Default 256 colour 8-bit indexed palette.]]
 +
<br clear="all">
 +
 
 +
Modern displays use 8-bit RGB values (0–255), but the Spectrum Next uses 3-bit values (0–7). This means converting colours will always involve some form of approximation or scaling.
 +
 
 +
The following image shows a palette calculated using linear scaling from 3-bit to 8-bit using:
 +
 
 +
<code>res = src × 255 ÷ 7</code>
 +
 
 +
 
 +
<br clear="all">

Latest revision as of 15:25, 8 April 2025

Palettes and Colour Mapping

To increase the number of available colours on screen, the Spectrum Next supports palletized colours. The number of displayable colours varies depending on the graphics mode:

  • ULA – 15 colours on screen at once (7 with optional BRIGHT - as bright black is still black), using 1 of 2 ULA palettes
  • ULANext – Up to 256 colours via attribute mapping, using 1 of 2 ULA Next palettes
  • Sprites – 16 colours per sprite (4-bit) with palette offsets or 256 colours (8-bit), using 1 of 2 sprite palettes
  • Layer 2 – Full 256-colour display, using 8-bit pixel values as palette indices, using 1 of 2 Layer2 palettes
  • Tilemap – One of two tilemap palettes used for final colour lookup.

Colour IDs in Layer 2, Sprites, and the ULA are treated as palette indices. These indices point to colours defined in the palette memory.

Setting Palette Colours

To define a colour in a palette:

  1. Use Enhanced ULA Control Register ($43) to select which palette to write to
  2. Use Palette Index Register ($40) to select the palette entry index
  3. Then send the colour using:
    1. Palette Value Register ($41) to send an 8-bit colour in RRRGGGBB format
    2. or Enhanced ULA Palette Extension ($44) to send a 9-bit colour, as two bytes:
      1. First byte: RRRGGGBB
      2. Second byte:
        • bit 0 = the third blue bit
        • For Layer 2: bit 7 = priority colour — forces the pixel to draw above all layers

Palette Value Register ($41) generates the missing third blue bit automatically as an OR of the other two. Both registers Palette Value Register ($41) and Enhanced ULA Palette Extension ($44) will auto-increment the palette index if auto-increment is enabled in Enhanced ULA Control Register ($43).

ULA and ULANext Colour Mapping

For the ULA, colour mapping behaves differently depending on the mode:

  • Standard ULA
    • INK: palette indices 0–7
    • BRIGHT INK: indices 8–15
    • PAPER and BORDER: indices 16–23 and 24–31

ULA+ is also avilable by enabling bit 3 of ULA Control Register ($68) with further information on how ULA+ works here : https://zxdesign.itch.io/ulaplus

Palette Registers in Detail

Palette Index Register ($40) – Palette Index

  • Selects the palette index to modify
  • This index will apply to whichever palette is selected via Enhanced ULA Control Register ($43)
  • Auto-increments after a write, if enabled
  • ULA-specific behaviour:
    • Standard INK = indices 0–7
    • Bright INK = 8–15
    • PAPER = 16–23
    • Bright PAPER = 24–31
    • In ULANext, INK uses a subset of 0–127 and PAPER uses 128–255
    • In ULA+ mode, the top 64 entries hold the ULA+ palette.
    • The ULA always takes border colour from paper for standard ULA and ULAnext.

Palette Value Register ($41) – 8-bit Colour Value

  • Writes an 8-bit colour value in RRRGGGBB format
  • The missing third blue bit is generated via OR of the two blue bits
  • Writing updates the current palette entry and increments the index (if auto-increment is enabled)
  • Reads do not auto-increment and only return the last 8-bit value

Enhanced ULA Ink Color Mask ($42) – ULANext Attribute Format

  • Defines how many bits of the ULA attribute byte represent INK (rest is PAPER)
  • Must be one of: 1, 3, 7, 15, 31, 63, 127, 255
  • INK index = base 0
  • PAPER + BORDER index = base 128
  • If not a valid mask, INK = attribute AND mask, and PAPER/BORDER use fallback from Transparency colour fallback Register ($4A)
  • The 255 value enables the full ink colour mode making all the palette entries INK. In this case PAPER and border are both taken from the fallback colour in nextreg 0x4A.
  • If the mask is not one of those listed above, the INK is taken as the logical AND of the mask with the attribute byte and the PAPER and border colour are again both taken from the fallback colour in (0x4A).

Enhanced ULA Control Register ($43) – Palette Control

  • bit 7 = Disable auto-increment
  • bits 6–4 = Select palette to write or read:
    • 000 = ULA 1st
    • 100 = ULA 2nd
    • 001 = Layer 2 1st
    • 101 = Layer 2 2nd
    • 010 = Sprites 1st
    • 110 = Sprites 2nd
    • 011 = Tilemap 1st
    • 111 = Tilemap 2nd
  • bit 3 = Use Sprites palette (0 = first palette, 1 = second palette) (soft reset = 0)
  • bit 2 = Use Layer 2 palette (0 = first palette, 1 = second palette) (soft reset = 0)
  • bit 1 = Use ULA palette (0 = first palette, 1 = second palette) (soft reset = 0)
  • bit 0 = Enable ULANext mode

Enhanced ULA Palette Extension ($44) – 9-bit Colour Value

  • Two consecutive writes are needed:
    • First byte: RRRGGGBB
    • Second byte: P000000B
      • bit 0 = third blue bit
      • For Layer 2: bit 7 = priority colour (Layer 2 pixel is drawn above all other layers). If you need the same colour in both priority and normal modes, you will need to have two different entries with the same colour one with and one without priority.
  • Auto-increments index if bit 7 is 0 in Enhanced ULA Control Register ($43)
  • Reads only return second byte - does not increment.
  • Writing to Palette Index Register ($40), Palette Value Register ($41), or Enhanced ULA Control Register ($43) resets to first write

Transparency colour fallback Register ($4A) – Fallback Colour

  • 8-bit colour used if all layers are transparent
  • Also used as PAPER/BORDER when ULANext attribute mask is invalid or set to 255 (soft reset = 0xe3)

Sprites Transparency Index Register ($4B) – Sprite Transparency Index

  • Sets which palette index will be treated as transparent in sprite rendering (soft reset = 0xe3)
  • Only bottom 4 bits are used for 4-bit sprites

Tilemap Transparency Index Register ($4C) – Tilemap Transparency Index

  • Lower 4 bits set the tilemap transparent colour index (soft reset = 0xf)
  • Upper 4 bits must be zero

Prepared Palette Files

The following palettes were created by Stefan Bylund for various graphics software:

Tool / Format 256 Colour Palette 512 Colour Palette
Photoshop .act
GIMP .gpl .gpl
JASC-PAL .pal .pal
Paint.NET .txt .txt

Only 256 colours can be displayed at once, even when using 512-colour palettes.

More tools and files by Stefan can be found here : github.com/stefanbylund/zxnext_bmp_tools

Palette Visuals

Default 256 colour 8-bit indexed palette.


Modern displays use 8-bit RGB values (0–255), but the Spectrum Next uses 3-bit values (0–7). This means converting colours will always involve some form of approximation or scaling.

The following image shows a palette calculated using linear scaling from 3-bit to 8-bit using:

res = src × 255 ÷ 7