“Ray, pretend for a moment that I don’t know anything about metallurgy, or engineering, or physics, and just tell me what the hell is going on.”
Right now I’m trying to figure out why The Legend of Zelda: Ocarina of Time’s boot screen has a frankly wrong color scheme, looking like this:

The problem, as far as I can tell, is that this boot screen uses one of the most complex Color Combiner setups that anything that boots in MESS attempts to use. Essentially, the N is supposed to have each face tinted to be the usual red / green / blue / yellow color scheme of the Nintendo 64 ‘N’ logo, with an environment-mapped texture blended onto the face with its own per-face tint as well.
The Color Combiner (CC) setup used in this scene is as follows:
Cycle 0 Color: ( C_TEX0 - C_PRIM ) * A_ENV + C_TEX0
Cycle 0 Alpha: 0 (simplified)
Cycle 1 Color: ( C_PRIM - C_ENV ) * C_COMBINED + C_ENV
Cycle 1 Alpha: 1 (simplified)
In plain (well, as plain as it can get) English, the Color Combiner implements the following equation for all four channels of a given pixel (R, G, B and A):
( A - B ) * C + D
For colors, A and B can be one of nine inputs (technically sixteen, but the last eight are the same):
- The combined color from the previous CC stage (C_COMBINED)
- The texel color from texture 0 (C_TEX0)
- The texel color from texture 1 (C_TEX1)
- The color stored in the Primitive Color register (C_PRIM)
- The triangle’s gouraud-shaded color for the current pixel (C_SHADE) (replaced by C_PRIM for non-triangle draw commands)
- The color stored in the Environment Color register (C_ENV)
- 1.0 (C_ONE)
- Randomized noise (C_NOISE, useful for static effects)
- 0.0 (C_ZERO, duplicated in selections 10-16)
For colors, C can be one of 17 inputs, (technically 32, but the last 16 are the same):
- The combined color from the previous CC stage (C_COMBINED)
- The texel color from texture 0 (C_TEX0)
- The texel color from texture 1 (C_TEX1)
- The color stored in the Primitive Color register (C_PRIM)
- The triangle’s gouraud-shaded color for the current pixel (C_SHADE) (replaced by C_PRIM for non-triangle draw commands)
- The color stored in the Environment Color register (C_ENV)
- The scaling value set by the Set Color Key command (color keying does not work on production N64 units)
- The combined alpha from the previous CC stage (A_COMBINED)
- The texel alpha from texture 0 (A_TEX0)
- The texel alpha from texture 1 (A_TEX1)
- The alpha value stored in the Primitive Color register (A_PRIM)
- The triangle’s gouraud-shaded alpha for the current pixel (A_SHADE) (replaced by A_PRIM for non-triangle draw commands)
- The alpha value stored in the Environment Color register (A_ENV)
- The fractional LOD value stepped from the triangle itself (LOD_FRAC, useful for blending between mipmaps of a texture)
- The fractional LOD value set by the most recent Set Primitive Color command (PRIM_LOD_FRAC, useful for blending between mipmaps of a texture)
- The K5 factor set by the most recent Set Convert command (CONV_K5, useful for hardware YUV conversion)
- 0.0 (duplicated in selections 18-32)
For colors, D can be one of eight inputs:
- The combined color from the previous CC stage (C_COMBINED)
- The texel color from texture 0 (C_TEX0)
- The texel color from texture 1 (C_TEX1)
- The color stored in the Primitive Color register (C_PRIM)
- The triangle’s gouraud-shaded color for the current pixel (C_SHADE) (replaced by C_PRIM for non-triangle draw commands)
- The color stored in the Environment Color register (C_ENV)
- 1.0 (C_ONE)
- 0.0 (C_ZERO)
For alpha values, A and B can be one of eight inputs:
- The combined alpha from the previous CC stage (A_COMBINED)
- The texel alpha from texture 0 (C_TEX0)
- The texel alpha from texture 1 (C_TEX1)
- The alpha value stored in the Primitive Color register (A_PRIM)
- The triangle’s gouraud-shaded alpha for the current pixel (A_SHADE) (replaced by A_PRIM for non-triangle draw commands)
- The alpha value stored in the Environment Color register (A_ENV)
- 1.0 (A_ONE)
- 0.0 (A_ZERO)
For alpha values, C can be one of eight inputs:
- The fractional LOD value stepped from the triangle itself (LOD_FRAC, useful for blending between mipmaps of a texture)
- The texel alpha from texture 0 (C_TEX0)
- The texel alpha from texture 1 (C_TEX1)
- The alpha value stored in the Primitive Color register (A_PRIM)
- The triangle’s gouraud-shaded alpha for the current pixel (A_SHADE) (replaced by A_PRIM for non-triangle draw commands)
- The alpha value stored in the Environment Color register (A_ENV)
- The non-fractional LOD value set by the most recent Set Primitive Color command (PRIM_LOD, useful for blending between mipmaps of a texture)
- 0.0 (A_ZERO)
For alpha values, D can be one of eight inputs. For the sake of brevity I’ll simply say that they’re the alpha equivalents of D’s inputs in the color equation.
All of this is pretty well-known already. That isn’t really the problem. The problem is figuring out how to handle overflow and underflow in the CC equation. I feel like I’m hitting my head against a brick wall, because none of the sensible answers that I’ve come up with so far seem to correspond to what actually happens on real hardware.
To simplify things a little, let’s concentrate on the left side of the N.
When the triangles in that face are drawn, the state of the Primitive Color register is 0xffaaffff (A255, R170, G255, B255) and the state of the Environment Color register is 0×80003296 (A128, R0, G50, B150).
To simplify things further, let’s kick the N64 into single-cycle mode and change the Cycle 0 Color equation to:
( C_ENV - C_PRIM ) * A_PRIM + C_ZERO
Since A_PRIM is 255 in this case, we can assume the equation simplifies further to just:
C_ENV - C_PRIM
With that in mind, filling the numbers in, we get:
- R: 0 - 170 = -170
- G: 50 - 255 = -205
- B: 150 - 255 = -105
On real hardware, we get:

As it stands, I’m at a loss as to how this manages to reduce down to yellow:
- If underflowing values are saturated to zero, then the color should be black.
- If the low 8 bits of the result are masked off prior to multiplication, then we get 0×00563397 (R:86, G:51, B:151), which doesn’t look anything like bright yellow.
- If the low 8 bits of the result are used after the multiplication, then we get 0×00AACD69 (R:170, G:205, B:105), which is a yellow-green color. Your first reaction may be to say that we’re getting closer, but none of the other faces are even close using that method, and it breaks Color Combiner functionality in pretty much all other cases as well.
I can’t think of any other ways this could work.
Can you? Post in the comments section if you think you have it sussed.