/******************************Module*Header**********************************\ * * ******************* * * DX SAMPLE CODE * * ******************* * * Module Name: chroma.h * * Content: Chromakeying definitions and inline functions * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #ifdef __CHROMA #pragma message ("FILE : "__FILE__" : Multiple inclusion") #endif #define __CHROMA //----------------------------------------------------------------------------- // // In this module we define the // // Get8888ScaledChroma // Get8888ZeroExtendedChroma // inline functions used to do texture chroma keying correctly. // // All other macros defined in this module are for internal module consumption // only. // //----------------------------------------------------------------------------- // Get the components for each of the colors // Put the value into the top bits of a byte. #define GET_RED_332(a) (((a) & 0xE0)) #define GET_GREEN_332(a) (((a) & 0x1C) << 3) #define GET_BLUE_332(a) (((a) & 0x03) << 6) #define GET_ALPHA_2321(a) (((a) & 0x80)) #define GET_RED_2321(a) (((a) & 0x60) << 1) #define GET_GREEN_2321(a) (((a) & 0x1C) << 3) #define GET_BLUE_2321(a) (((a) & 0x03) << 6) #define GET_ALPHA_5551(a) (((a) & 0x8000) >> 8) #define GET_RED_5551(a) (((a) & 0x7C00) >> 7) #define GET_GREEN_5551(a) (((a) & 0x03E0) >> 2) #define GET_BLUE_5551(a) (((a) & 0x001F) << 3) #define GET_RED_565(a) (((a) & 0xF800) >> 8) #define GET_GREEN_565(a) (((a) & 0x07E0) >> 3) #define GET_BLUE_565(a) (((a) & 0x001F) << 3) #define GET_ALPHA_4444(a) (((a) & 0xF000) >> 8) #define GET_RED_4444(a) (((a) & 0x0F00) >> 4) #define GET_GREEN_4444(a) (((a) & 0x00F0)) #define GET_BLUE_4444(a) (((a) & 0x000F) << 4) #define GET_ALPHA_8888(a) (((a) & 0xFF000000) >> 24) #define GET_RED_8888(a) (((a) & 0x00FF0000) >> 16) #define GET_GREEN_8888(a) (((a) & 0x0000FF00) >> 8) #define GET_BLUE_8888(a) (((a) & 0x000000FF)) // These macros assume that the passed value (a) contains no more than the // designated number of bits set i.e. 11111000 not 1111101 for a 5 bit color // The macro scales the number to match the internal color conversion of // Permedia3. #define P3SCALE_1_BIT(a) (((a) & 0x80) ? 0xFF : 0x0) #define P3SCALE_2_BIT(a) ((a) | (((a) & 0xC0) >> 2) \ | (((a) & 0xC0) >> 4) \ | (((a) & 0xC0) >> 6)) #define P3SCALE_3_BIT(a) ((a) | (((a) & 0xE0) >> 3) | (((a) & 0xC0) >> 6)) #define P3SCALE_4_BIT(a) ((a) | (((a) & 0xF0) >> 4)) #define P3SCALE_5_BIT(a) ((a) | (((a) & 0xE0) >> 5)) #define P3SCALE_6_BIT(a) ((a) | (((a) & 0xC0) >> 6)) #define P3SCALE_7_BIT(a) ((a) | (((a) & 0x80) >> 7)) #define P3SCALE_8_BIT(a) ((a)) #define P3REG_PLACE_RED(a) ((a)) #define P3REG_PLACE_GREEN(a) ((a) << 8) #define P3REG_PLACE_BLUE(a) ((a) << 16) #define P3REG_PLACE_ALPHA(a) ((a) << 24) // The scaling versions. #define GEN_332_KEY(a) (P3REG_PLACE_RED (P3SCALE_3_BIT(GET_RED_332 (a))) | \ P3REG_PLACE_GREEN(P3SCALE_3_BIT(GET_GREEN_332(a))) | \ P3REG_PLACE_BLUE (P3SCALE_2_BIT(GET_BLUE_332 (a)))) #define GEN_2321_KEY(a) (P3REG_PLACE_ALPHA(P3SCALE_1_BIT(GET_ALPHA_2321(a))) | \ P3REG_PLACE_RED (P3SCALE_2_BIT(GET_RED_2321 (a))) | \ P3REG_PLACE_GREEN(P3SCALE_3_BIT(GET_GREEN_2321(a))) | \ P3REG_PLACE_BLUE (P3SCALE_2_BIT(GET_BLUE_2321 (a)))) #define GEN_5551_KEY(a) (P3REG_PLACE_ALPHA(P3SCALE_1_BIT(GET_ALPHA_5551(a))) | \ P3REG_PLACE_RED (P3SCALE_5_BIT(GET_RED_5551 (a))) | \ P3REG_PLACE_GREEN(P3SCALE_5_BIT(GET_GREEN_5551(a))) | \ P3REG_PLACE_BLUE (P3SCALE_5_BIT(GET_BLUE_5551 (a)))) #define GEN_565_KEY(a) (P3REG_PLACE_RED (P3SCALE_5_BIT(GET_RED_565 (a))) | \ P3REG_PLACE_GREEN(P3SCALE_6_BIT(GET_GREEN_565(a))) | \ P3REG_PLACE_BLUE (P3SCALE_5_BIT(GET_BLUE_565 (a)))) #define GEN_4444_KEY(a) (P3REG_PLACE_ALPHA(P3SCALE_4_BIT(GET_ALPHA_4444(a))) | \ P3REG_PLACE_RED (P3SCALE_4_BIT(GET_RED_4444 (a))) | \ P3REG_PLACE_GREEN(P3SCALE_4_BIT(GET_GREEN_4444(a))) | \ P3REG_PLACE_BLUE (P3SCALE_4_BIT(GET_BLUE_4444 (a)))) #define GEN_8888_KEY(a) (P3REG_PLACE_ALPHA(P3SCALE_8_BIT(GET_ALPHA_8888(a))) | \ P3REG_PLACE_RED (P3SCALE_8_BIT(GET_RED_8888 (a))) | \ P3REG_PLACE_GREEN(P3SCALE_8_BIT(GET_GREEN_8888(a))) | \ P3REG_PLACE_BLUE (P3SCALE_8_BIT(GET_BLUE_8888 (a)))) // The shifting versions. #define GEN_332_SKEY(a) (P3REG_PLACE_RED (GET_RED_332 (a)) | \ P3REG_PLACE_GREEN(GET_GREEN_332(a)) | \ P3REG_PLACE_BLUE (GET_BLUE_332 (a))) #define GEN_2321_SKEY(a) (P3REG_PLACE_ALPHA(GET_ALPHA_2321(a)) | \ P3REG_PLACE_RED (GET_RED_2321 (a)) | \ P3REG_PLACE_GREEN(GET_GREEN_2321(a)) | \ P3REG_PLACE_BLUE (GET_BLUE_2321 (a))) #define GEN_5551_SKEY(a) (P3REG_PLACE_ALPHA(GET_ALPHA_5551(a)) | \ P3REG_PLACE_RED (GET_RED_5551 (a)) | \ P3REG_PLACE_GREEN(GET_GREEN_5551(a)) | \ P3REG_PLACE_BLUE (GET_BLUE_5551 (a))) #define GEN_565_SKEY(a) (P3REG_PLACE_RED (GET_RED_565 (a)) | \ P3REG_PLACE_GREEN(GET_GREEN_565(a)) | \ P3REG_PLACE_BLUE (GET_BLUE_565 (a))) #define GEN_4444_SKEY(a) (P3REG_PLACE_ALPHA(GET_ALPHA_4444(a)) | \ P3REG_PLACE_RED (GET_RED_4444 (a)) | \ P3REG_PLACE_GREEN(GET_GREEN_4444(a)) | \ P3REG_PLACE_BLUE (GET_BLUE_4444 (a))) // The luminance versions #define GEN_L8_KEY(a) (P3REG_PLACE_ALPHA(0xFF) | \ P3REG_PLACE_RED (GET_BLUE_8888 (a)) | \ P3REG_PLACE_GREEN(GET_BLUE_8888 (a)) | \ P3REG_PLACE_BLUE (GET_BLUE_8888 (a))) #define GEN_A8L8_KEY(a) (P3REG_PLACE_ALPHA(GET_GREEN_8888 (a)) | \ P3REG_PLACE_RED (GET_BLUE_8888 (a)) | \ P3REG_PLACE_GREEN(GET_BLUE_8888 (a)) | \ P3REG_PLACE_BLUE (GET_BLUE_8888 (a))) #define GEN_A4L4_KEY(a) (P3REG_PLACE_ALPHA(P3SCALE_4_BIT(GET_GREEN_4444 (a))) | \ P3REG_PLACE_RED (P3SCALE_4_BIT(GET_BLUE_4444 (a))) | \ P3REG_PLACE_GREEN(P3SCALE_4_BIT(GET_BLUE_4444 (a))) | \ P3REG_PLACE_BLUE (P3SCALE_4_BIT(GET_BLUE_4444 (a)))) //Note: No GEN_8888_SKEY - no difference in functionality. //----------------------------------------------------------------------------- // // __inline Get8888ScaledChroma // // Convert a FB Format color to a colorkey value. The value produced exactly // matches the value that the chip will read in from the Framebuffer (it will // scale the color into it's internal 8888 format). Non-null pPalEntries // indicates that color index should be converted to RGB{A} value. bUsePalAlpha // indicates whether Alpha channel of the palette should be used. bShift makes // the conversion use a shift instead of a scale, to match the shift option in // the P3. // //----------------------------------------------------------------------------- static __inline void Get8888ScaledChroma( P3_THUNKEDDATA* pThisDisplay, DWORD dwSurfFlags, DDPIXELFORMAT* pSurfPixFormat, DWORD InLowerBound, DWORD InUpperBound, DWORD* OutLowerBound, DWORD* OutUpperBound, DWORD* pPalEntries, BOOL bUsePalAlpha, BOOL bShift) { DDPIXELFORMAT* pPixFormat; DISPDBG((DBGLVL, "InLowerBound = 0x%08X", InLowerBound)); DISPDBG((DBGLVL, "InUpperBound = 0x%08X", InUpperBound)); // Get a pointer to the pixelformat data (not guaranteed to exist. // If it doesn't, we use the same format as the display. if (DDSurf_HasPixelFormat(dwSurfFlags)) { pPixFormat = pSurfPixFormat; } else { pPixFormat = &pThisDisplay->ddpfDisplay; } // Is the texture palette indexed? if (pPixFormat->dwFlags & DDPF_PALETTEINDEXED4 || pPixFormat->dwFlags & DDPF_PALETTEINDEXED8) { // Are we doing a lookup through the LUT? We won't be during a blit if (! pPalEntries) { *OutLowerBound = CHROMA_LOWER_ALPHA(FORMAT_PALETTE_32BIT(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(FORMAT_PALETTE_32BIT(InUpperBound)); DISPDBG((DBGLVL,"Keying of index: %d", InLowerBound)); } else { DWORD dwTrueColor; // ChromaKeying for paletted textures is done on the looked up // color, not the index. This means using a range is meaningless // and we have to lookup the color from the palette. Make sure // the user doesn't force us to access invalid memory. dwTrueColor = pPalEntries[(InLowerBound & 0xFF)]; DISPDBG((DBGLVL, "Texture lookup index: %d, ChromaColor: 0x%x", InLowerBound, dwTrueColor)); if (bUsePalAlpha) { *OutLowerBound = dwTrueColor; *OutUpperBound = dwTrueColor; } else { // Alpha channel of LUT will be set to FF *OutLowerBound = CHROMA_LOWER_ALPHA(dwTrueColor); *OutUpperBound = CHROMA_UPPER_ALPHA(dwTrueColor); } } return; } // Texture is RGB format if (pPixFormat->dwFlags & DDPF_RGB) { DWORD RedMask = pPixFormat->dwRBitMask; DWORD AlphaMask = pPixFormat->dwRGBAlphaBitMask; switch (pPixFormat->dwRGBBitCount) { // 8 Bit RGB Textures case 8: if (RedMask == 0xE0) { DISPDBG((DBGLVL," 3:3:2")); // Never any alpha if ( bShift ) { *OutLowerBound = CHROMA_LOWER_ALPHA(GEN_332_SKEY(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(GEN_332_SKEY(InUpperBound)); } else { *OutLowerBound = CHROMA_LOWER_ALPHA(GEN_332_KEY(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(GEN_332_KEY(InUpperBound)); } } else { DISPDBG((DBGLVL," 1:2:3:2")); if ( bShift ) { *OutLowerBound = GEN_2321_SKEY(InLowerBound); *OutUpperBound = GEN_2321_SKEY(InUpperBound); } else { *OutLowerBound = GEN_2321_KEY(InLowerBound); *OutUpperBound = GEN_2321_KEY(InUpperBound); } if (!AlphaMask) { *OutLowerBound = CHROMA_LOWER_ALPHA(*OutLowerBound); *OutUpperBound = CHROMA_UPPER_ALPHA(*OutUpperBound); } } break; // 16 Bit RGB Textures case 16: switch (RedMask) { case 0xf00: DISPDBG((DBGLVL," 4:4:4:4")); if ( bShift ) { *OutLowerBound = GEN_4444_SKEY(InLowerBound); *OutUpperBound = GEN_4444_SKEY(InUpperBound); } else { *OutLowerBound = GEN_4444_KEY(InLowerBound); *OutUpperBound = GEN_4444_KEY(InUpperBound); } break; case 0x7c00: DISPDBG((DBGLVL," 1:5:5:5")); if ( bShift ) { *OutLowerBound = GEN_5551_SKEY(InLowerBound); *OutUpperBound = GEN_5551_SKEY(InUpperBound); } else { *OutLowerBound = GEN_5551_KEY(InLowerBound); *OutUpperBound = GEN_5551_KEY(InUpperBound); } if (!AlphaMask) { *OutLowerBound = CHROMA_LOWER_ALPHA(*OutLowerBound); *OutUpperBound = CHROMA_UPPER_ALPHA(*OutUpperBound); } break; default: // Always supply full range of alpha values to ensure test // is done DISPDBG((DBGLVL," 5:6:5")); if ( bShift ) { *OutLowerBound = CHROMA_LOWER_ALPHA(GEN_565_SKEY(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(GEN_565_SKEY(InUpperBound)); } else { *OutLowerBound = CHROMA_LOWER_ALPHA(GEN_565_KEY(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(GEN_565_KEY(InUpperBound)); } break; } // switch (RedMask) break; // 32/24 Bit RGB Textures case 24: case 32: DISPDBG((DBGLVL," 8:8:8:8")); // If the surface isn't alpha'd then set a valid // range of alpha to catch all cases. // No change in behavior for shifting or scaling. if (!AlphaMask) { *OutLowerBound = CHROMA_LOWER_ALPHA(GEN_8888_KEY(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(GEN_8888_KEY(InUpperBound)); } else { *OutLowerBound = GEN_8888_KEY(InLowerBound); *OutUpperBound = GEN_8888_KEY(InUpperBound); } break; } // switch (pPixFormat->dwRGBBitCount) DISPDBG((DBGLVL, "OutLowerBound = 0x%08X", *OutLowerBound)); DISPDBG((DBGLVL, "OutUpperBound = 0x%08X", *OutUpperBound)); } // luminance formats else if (pPixFormat->dwFlags & DDPF_LUMINANCE) { if (pPixFormat->dwFlags & DDPF_ALPHAPIXELS) { if (pPixFormat->dwLuminanceBitCount == 16) { // 16 bit A8L8 *OutLowerBound = GEN_A8L8_KEY(InLowerBound); *OutUpperBound = GEN_A8L8_KEY(InUpperBound); } else { // 8 Bit A4L4 *OutLowerBound = GEN_A4L4_KEY(InLowerBound); *OutUpperBound = GEN_A4L4_KEY(InUpperBound); } } else { // 8 Bit L8 *OutLowerBound = GEN_L8_KEY(InLowerBound); *OutUpperBound = GEN_L8_KEY(InUpperBound); } } //@@BEGIN_DDKSPLIT //AZN - just keep in case we find an app requiring this (Legoland???) #if 0 if ( TEST_BUGFIX_FLAG ( IGNORE_CK_ALPHA ) ) { // Fix it up for games that don't realise that they // need to set up the alpha-channel of the chromakey // values appropriately. *OutLowerBound = CHROMA_LOWER_ALPHA(*OutLowerBound); *OutUpperBound = CHROMA_UPPER_ALPHA(*OutUpperBound); } #endif //@@END_DDKSPLIT } // Get8888ScaledChroma //----------------------------------------------------------------------------- // // __inline Get8888ZeroExtendedChroma // //----------------------------------------------------------------------------- __inline void Get8888ZeroExtendedChroma( P3_THUNKEDDATA* pThisDisplay, DWORD dwSurfFlags, DDPIXELFORMAT* pSurfPixFormat, DWORD LowerBound, DWORD UpperBound, DWORD* OutLowerBound, DWORD* OutUpperBound) { DDPIXELFORMAT* pPixFormat; DWORD InLowerBound = LowerBound; DWORD InUpperBound = UpperBound; DISPDBG((DBGLVL, "InLowerBound = 0x%08X", InLowerBound)); DISPDBG((DBGLVL, "InUpperBound = 0x%08X", InUpperBound)); // Get a pointer to the pixelformat data (not guaranteed to exist. // If it doesn't, we use the same format as the display. if (DDSurf_HasPixelFormat(dwSurfFlags)) { pPixFormat = pSurfPixFormat; } else { pPixFormat = &pThisDisplay->ddpfDisplay; } { DWORD RedMask = pPixFormat->dwRBitMask; DWORD AlphaMask = pPixFormat->dwRGBAlphaBitMask; switch (pPixFormat->dwRGBBitCount) { // 8 Bit RGB Textures case 8: if (RedMask == 0xE0) { // Never any alpha *OutLowerBound = CHROMA_LOWER_ALPHA(FORMAT_332_32BIT_ZEROEXTEND(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(FORMAT_332_32BIT_ZEROEXTEND(InUpperBound)); } else { *OutLowerBound = FORMAT_2321_32BIT_ZEROEXTEND(InLowerBound); *OutUpperBound = FORMAT_2321_32BIT_ZEROEXTEND(InUpperBound); if (!AlphaMask) { *OutLowerBound = CHROMA_LOWER_ALPHA(*OutLowerBound); *OutUpperBound = CHROMA_UPPER_ALPHA(*OutUpperBound); } } break; // 16 Bit RGB Textures case 16: switch (RedMask) { case 0xf00: *OutLowerBound = (FORMAT_4444_32BIT_ZEROEXTEND(InLowerBound)); *OutUpperBound = (FORMAT_4444_32BIT_ZEROEXTEND(InUpperBound)); break; case 0x7c00: *OutLowerBound = FORMAT_5551_32BIT_ZEROEXTEND(InLowerBound); *OutUpperBound = FORMAT_5551_32BIT_ZEROEXTEND(InUpperBound); if (!AlphaMask) { *OutLowerBound = CHROMA_LOWER_ALPHA(*OutLowerBound); *OutUpperBound = CHROMA_UPPER_ALPHA(*OutUpperBound); } break; default: // Always supply full range of alpha values to ensure test // is done *OutLowerBound = CHROMA_LOWER_ALPHA(FORMAT_565_32BIT_ZEROEXTEND(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(FORMAT_565_32BIT_ZEROEXTEND(InUpperBound)); break; } break; // 32/24 Bit RGB Textures case 24: case 32: // If the surface isn't alpha'd then set a valid // range of alpha to catch all cases. if (!AlphaMask) { *OutLowerBound = CHROMA_LOWER_ALPHA(FORMAT_8888_32BIT_BGR(InLowerBound)); *OutUpperBound = CHROMA_UPPER_ALPHA(FORMAT_8888_32BIT_BGR(InUpperBound)); } else { *OutLowerBound = FORMAT_8888_32BIT_BGR(InLowerBound); *OutUpperBound = FORMAT_8888_32BIT_BGR(InUpperBound); } break; } // switch (pPixFormat->dwRGBBitCount) DISPDBG((DBGLVL, "OutLowerBound = 0x%08X", *OutLowerBound)); DISPDBG((DBGLVL, "OutUpperBound = 0x%08X", *OutUpperBound)); } //@@BEGIN_DDKSPLIT //AZN - just keep in case we find an app requiring this (Legoland???) #if 0 if ( TEST_BUGFIX_FLAG ( IGNORE_CK_ALPHA ) ) { // Fix it up for games that don't realise that they // need to set up the alpha-channel of the chromakey // values appropriately. *OutLowerBound = CHROMA_LOWER_ALPHA(*OutLowerBound); *OutUpperBound = CHROMA_UPPER_ALPHA(*OutUpperBound); } #endif //@@END_DDKSPLIT } // Get8888ZeroExtendedChroma