Skip to content →

sub screens & color math

Another important step to conquer the SNES‘ complex graphics is to understand the concept of main screens and sub screens.

Every BG can be enabled for a main screen and/or for a sub screen. The main screens are the ones with already work with all the time and that are being blended together and rendered to the screen. Sub screens are only used for color math, so for image effects like translucency, shading etc.
Despite what they are set to, or not set to, main screens and their respective sub screens always hold the same data.

Main screens are enabled using the register 0x212C, the sub screens using the register 0x212D

BitDescription
Bit 0BG1 (0 – Disabled, 1 – Enabled)
Bit 1BG2 (0 – Disabled, 1 – Enabled)
Bit 2BG3 (0 – Disabled, 1 – Enabled)
Bit 3BG4 (0 – Disabled, 1 – Enabled)
Bit 4OBJ (0 – Disabled, 1 – Enabled)
Bit 5 – 7not used

The general switch to enable Color Math is in bits 4 and 5 register 0x2130 (Color Math Control Register A)

BitDescriptionSettings
Bit 0Direct Color0 – use palette, 1 – use direct color in 256 col mode
Bit 1Sub Screen BG/OBJ Enable0 – Backdrop only, 1 – Backdrop/BG/OBJ
Bit 2 – 3/not used
Bit 4 – 5Enable Color Math0 – always, 1 – MathWindow, 2 – NotMathWindow, 3 – never
Bit 6 – 7Force Main Screen Black0 – never, 1 – NotMathWindow, 2 – MathWindow, 3 – alway

Additionally, the Backgrounds have to be enabled for Color Math in the additional register 0x2131 (Color Math Control Register B)

BitDescriptionSettings
Bit 0Color Math for BG10 – disabled, 1 – enabled
Bit 1Color Math for BG20 – disabled, 1 – enabled
Bit 2Color Math for BG30 – disabled, 1 – enabled
Bit 3Color Math for BG40 – disabled, 1 – enabled
Bit 4Color Math for OBJ/Palette 4 – 70 – disabled, 1 – enabled
Bit 5Color Math for Backdrop0 – disabled, 1 – enabled
Bit 6Div20 – no division, 1 – divide result by 2
Bit 7Add/Sub mode0 – add, 1 – subtract

With Bit 7 we can select if the sub screens are supposed to added or subtracted from the main screens, which is what ultimately creates the image effects. Bit 6 can optionally dictate to divide the result 2, so the effect is not that ‘hard’.

Color Math can be disabled by setting Bits 4-5 of 0x2130, or by clearing Bits 0-5 of 0x2131. 
When it is disabled, only the Main Screen is displayed, and the Sub Screen has no effect on the display. 

The actual additions and subtractions to the main screens are simple additions and subtractions, per color channel, clamped to 0, respectively 255. For the addition, SDL luckily already offers a blend mode, so it’s not much that we have to do:

// example for a single BG
SDL_BlendMode COLOR_MATH_REG_B_ADD_SUB = SDL_BLENDMODE_ADD;
...
if (BG_ENABLED[0]) {
	SDL_RenderCopy(renderer, TEXTURE[0], NULL, NULL);
	//	SubScreens
	if (COLOR_MATH_REG_A_COLOR_MATH_ENABLE == 0) {
		if (SUB_ENABLED[3] && SUB_COLMATH_ENABLED[0]) {
			SDL_SetTextureBlendMode(TEXTURE[3], COLOR_MATH_REG_B_ADD_SUB);
			SDL_RenderCopy(renderer, TEXTURE[3], NULL, NULL);
		}
		if (SUB_ENABLED[2] && SUB_COLMATH_ENABLED[0]) {
			SDL_SetTextureBlendMode(TEXTURE[2], COLOR_MATH_REG_B_ADD_SUB);
			SDL_RenderCopy(renderer, TEXTURE[2], NULL, NULL);
		}
		if (SUB_ENABLED[1] && SUB_COLMATH_ENABLED[0]) {
			SDL_SetTextureBlendMode(TEXTURE[1], COLOR_MATH_REG_B_ADD_SUB);
			SDL_RenderCopy(renderer, TEXTURE[1], NULL, NULL);
		}
		if (SUB_ENABLED[0] && SUB_COLMATH_ENABLED[0]) {
			SDL_SetTextureBlendMode(TEXTURE[0], COLOR_MATH_REG_B_ADD_SUB);
			SDL_RenderCopy(renderer, TEXTURE[0], NULL, NULL);
		}
	}
}

We are lacking the subtraction blend mode though. But SDL offers us the ability to create custom blend modes, which is a very handy tool for us now, because we can create a static blend mode that we can use for the rest of the code.

const SDL_BlendMode SDL_BLENDMODE_SUB = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_REV_SUBTRACT, SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD);

To actually test our blending and our first steps in color math, we run (of course) more tests from krom.

kroms Hicolor Myst 575 demo

This is, like already explained, done by the simple additional blending, which is nothing but adding color per channel. For example if we look at the sky in that images, the following happens:

Color Math – adding

The same happens for the subtraction we implemented (just being clamped down to 0x00 instead of 0xFF per channel). But since krom’s test are only working with add, I modified the source code of the test(s), to use subtract instead. The palettes are created with adding in mind though, so I changed the palette of the sub screen as well, so we can cleary see some changes in the end result. The result is not pretty, but we only need to be able to verify it’s correct in comparison to hardware (or other emulators).

Color Math – subtracting

After we verified that subtracting works just as well, we can run the other 2 test as well, to confirm everything works as intended.

kroms Hicolor 1241 DLair test
kroms Hicolor 3840 test

Comments

Leave a Reply