2020-07-31 11:31:32 +08:00
|
|
|
//===============================================================================
|
|
|
|
// Copyright (c) 2007-2016 Advanced Micro Devices, Inc. All rights reserved.
|
|
|
|
// Copyright (c) 2004-2006 ATI Technologies Inc.
|
|
|
|
//===============================================================================
|
|
|
|
//
|
|
|
|
// Project ATI Handheld Graphics - Texture Compression
|
|
|
|
//
|
|
|
|
// Description This source code is part of the ATI handheld texture compression library.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files(the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions :
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
// THE SOFTWARE.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#if defined(__ARM__)
|
|
|
|
#include <string.h>
|
|
|
|
#else
|
|
|
|
#include <memory.h>
|
|
|
|
#endif
|
|
|
|
#include <stdio.h>
|
2021-09-08 10:54:22 +08:00
|
|
|
#include "compressonator_tc.h"
|
2020-07-31 11:31:32 +08:00
|
|
|
|
|
|
|
#ifndef BOOL
|
|
|
|
typedef int BOOL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef TRUE
|
|
|
|
#define TRUE (1==1)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef FALSE
|
|
|
|
#define FALSE (1==0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef min
|
|
|
|
#define min(A,B) ((A) < (B) ? (A) : (B))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef max
|
|
|
|
#define max(A,B) ((A) > (B) ? (A) : (B))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef HIWORD
|
|
|
|
#define HIWORD(N32) ((unsigned short)(((unsigned long)(N32) >> 16) & 0x0000FFFF))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef LOWORD
|
|
|
|
#define LOWORD(N32) ((unsigned short)((N32) & 0x0000FFFF))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// WARNING: Do not change the luminance calculation! It needs to match the hardware exactly.
|
|
|
|
#define LUMINANCE(R, G, B) ((19*(R) + 38*(G) + 7*(B))>>6)
|
|
|
|
|
|
|
|
|
|
|
|
typedef long MSE_t;
|
|
|
|
#define MSE_ZERO 0
|
|
|
|
#define MSE_HIGHEST 255 * 255 * 16
|
|
|
|
|
|
|
|
static long
|
|
|
|
ErrSquared( const Color888_t *pColor1, const Color888_t *pColor2 )
|
|
|
|
{
|
|
|
|
long errorRed, errorGreen, errorBlue;
|
|
|
|
|
|
|
|
errorRed = ((long)pColor1->red - pColor2->red);
|
|
|
|
errorGreen = ((long)pColor1->green - pColor2->green);
|
|
|
|
errorBlue = ((long)pColor1->blue - pColor2->blue);
|
|
|
|
|
|
|
|
return ((errorRed * errorRed ) +
|
|
|
|
(errorGreen * errorGreen) +
|
|
|
|
(errorBlue * errorBlue ));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define DIFF(A,B) ((A)>(B) ? (A)-(B) : (B)-(A))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Color888To565() - Converts an 8:8:8 color to a 5:6:5 color. Notice
|
|
|
|
* that the code doesn't just throw away the low bits.
|
|
|
|
* It chooses the 5:6:5 value that will be closest to
|
|
|
|
* the original color when expanded back to 8:8:8. For
|
|
|
|
* example, a niave conversion would convert (7,3,7) to
|
|
|
|
* (0,0,0) while a smarter algorithm would convert it to
|
|
|
|
* (8,4,8) because it will expand back to a color closer
|
|
|
|
* to the original.
|
|
|
|
*/
|
|
|
|
static unsigned int
|
|
|
|
Color888To565( const Color888_t *pColor888 )
|
|
|
|
{
|
|
|
|
unsigned int r, g, b;
|
|
|
|
unsigned int r_a, g_a, b_a, r_b, g_b, b_b;
|
|
|
|
|
|
|
|
r = pColor888->red;
|
|
|
|
g = pColor888->green;
|
|
|
|
b = pColor888->blue;
|
|
|
|
|
|
|
|
r_a = (r & 0x000000F8) | (r & 0x000000E0) >> 5;
|
|
|
|
g_a = (g & 0x000000FC) | (g & 0x000000C0) >> 6;
|
|
|
|
b_a = (b & 0x000000F8) | (b & 0x000000E0) >> 5;
|
|
|
|
|
|
|
|
r_b = r_a ^ 0x00000008;
|
|
|
|
g_b = g_a ^ 0x00000004;
|
|
|
|
b_b = b_a ^ 0x00000008;
|
|
|
|
|
|
|
|
if ( DIFF(r, r_b) < DIFF(r, r_a) ) r = r_b;
|
|
|
|
if ( DIFF(g, g_b) < DIFF(g, g_a) ) g = g_b;
|
|
|
|
if ( DIFF(b, b_b) < DIFF(b, b_a) ) b = b_b;
|
|
|
|
|
|
|
|
return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
Color565To888( unsigned int color565, Color888_t *pColor888Ret )
|
|
|
|
{
|
|
|
|
pColor888Ret->red = (unsigned char)(((color565 & 0x0000F800) >> 8) | ((color565 & 0x0000E000) >> 13));
|
|
|
|
pColor888Ret->green = (unsigned char)(((color565 & 0x000007E0) >> 3) | ((color565 & 0x00000600) >> 9));
|
|
|
|
pColor888Ret->blue = (unsigned char)(((color565 & 0x0000001F) << 3) | ((color565 & 0x0000001C) >> 2));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Color888To1555() - Converts an 8:8:8 color to a 1:5:5:5 color. The high bit
|
|
|
|
* is used to hold "boolBlackTrick"
|
|
|
|
*/
|
|
|
|
static unsigned int
|
|
|
|
Color888To1555( const Color888_t *pColor888, BOOL boolBlackTrick )
|
|
|
|
{
|
|
|
|
unsigned int r, g, b;
|
|
|
|
unsigned int r_a, g_a, b_a, r_b, g_b, b_b;
|
|
|
|
unsigned int color1555;
|
|
|
|
|
|
|
|
r = pColor888->red;
|
|
|
|
g = pColor888->green;
|
|
|
|
b = pColor888->blue;
|
|
|
|
|
|
|
|
r_a = (r & 0x000000F8) | (r & 0x000000E0) >> 5;
|
|
|
|
g_a = (g & 0x000000F8) | (g & 0x000000e0) >> 5;
|
|
|
|
b_a = (b & 0x000000F8) | (b & 0x000000E0) >> 5;
|
|
|
|
|
|
|
|
r_b = r_a ^ 0x00000008;
|
|
|
|
g_b = g_a ^ 0x00000008;
|
|
|
|
b_b = b_a ^ 0x00000008;
|
|
|
|
|
|
|
|
if ( DIFF(r, r_b) < DIFF(r, r_a) ) r = r_b;
|
|
|
|
if ( DIFF(g, g_b) < DIFF(g, g_a) ) g = g_b;
|
|
|
|
if ( DIFF(b, b_b) < DIFF(b, b_a) ) b = b_b;
|
|
|
|
|
|
|
|
color1555 = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
|
|
|
|
return (boolBlackTrick ? color1555 | 0x00008000 : color1555);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Color1555To888() - In addition to the conversion, this function returns a boolean
|
|
|
|
* TRUE or FALSE indicating if the high bit is set.
|
|
|
|
*/
|
|
|
|
static BOOL
|
|
|
|
Color1555To888( unsigned int color1555, Color888_t *pColor888Ret )
|
|
|
|
{
|
|
|
|
BOOL boolBlackTrick = color1555 & 0x00008000;
|
|
|
|
|
|
|
|
pColor888Ret->red = (unsigned char)(((color1555 & 0x00007C00) >> 7) | ((color1555 & 0x00007000) >> 12));
|
|
|
|
pColor888Ret->green = (unsigned char)(((color1555 & 0x000003E0) >> 2) | ((color1555 & 0x00000380) >> 7));
|
|
|
|
pColor888Ret->blue = (unsigned char)(((color1555 & 0x0000001F) << 3) | ((color1555 & 0x0000001C) >> 2));
|
|
|
|
|
|
|
|
return boolBlackTrick;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ColorBrightness() - returns the color brightness percentage (0-100).
|
|
|
|
*
|
|
|
|
* Return values:
|
|
|
|
*
|
|
|
|
* < ~14% means color is very close to black
|
|
|
|
*
|
|
|
|
* < ~11% means color is very close to pitch black
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ColorBrightness( Color888_t *pColor888 )
|
|
|
|
{
|
|
|
|
unsigned int maximum;
|
|
|
|
int value;
|
|
|
|
|
|
|
|
maximum = max( max( pColor888->red , pColor888->green ), pColor888->blue );
|
|
|
|
value = (maximum * 100) / 255;
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ColorHueAndSaturation() - Returns the hue of the color in degrees (0-360).
|
|
|
|
* If saturation is zero, hue is undefined and returned
|
|
|
|
* as -1;
|
|
|
|
*
|
|
|
|
* Also returns the saturation of the color as a percentage
|
|
|
|
* between 0 and 100.
|
|
|
|
*
|
|
|
|
* Return values:
|
|
|
|
*
|
|
|
|
* saturation < ~5% means color is a shade of gray between black & white
|
|
|
|
*
|
|
|
|
* < ~11% means color is a shade of gray between black & white
|
|
|
|
* but may have a slight hint of color
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ColorHueAndSaturation( Color888_t *pColor888,
|
|
|
|
int *pOut_Hue, // Return value
|
|
|
|
int *pOut_Saturation // Return value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
unsigned int maximum, minimum, deltaMinMax;
|
|
|
|
int hue, saturation;
|
|
|
|
unsigned int red, green, blue;
|
|
|
|
|
|
|
|
red = pColor888->red;
|
|
|
|
green = pColor888->green;
|
|
|
|
blue = pColor888->blue;
|
|
|
|
|
|
|
|
minimum = min( min( red , green ), blue );
|
|
|
|
maximum = max( max( red , green ), blue );
|
|
|
|
deltaMinMax = maximum - minimum;
|
|
|
|
|
|
|
|
//--------------------------
|
|
|
|
// Calculate the saturation
|
|
|
|
//--------------------------
|
|
|
|
|
|
|
|
saturation = (maximum != 0) ? (deltaMinMax * 100) / maximum : 0;
|
|
|
|
|
|
|
|
//-------------------
|
|
|
|
// Calculate the hue
|
|
|
|
//-------------------
|
|
|
|
|
|
|
|
if ( saturation == 0)
|
|
|
|
hue = -1; // Hue is undefined when saturation is zero
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( red == maximum )
|
|
|
|
hue = (int)((((float)green - blue) / deltaMinMax) * 60); // Color is between yellow & magenta
|
|
|
|
else if ( green == maximum )
|
|
|
|
hue = (int)((2 + ((float)blue - red) / deltaMinMax) * 60); // Color is between cyan and yellow
|
|
|
|
else
|
|
|
|
hue = (int)((4 + ((float)red - green) / deltaMinMax) * 60); // Color is between magenta and cyan
|
|
|
|
|
|
|
|
hue = (hue < 0) ? hue + 360 : hue; // Make sure hue isn't negative
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------
|
|
|
|
// Return the results
|
|
|
|
//--------------------
|
|
|
|
|
|
|
|
if ( pOut_Hue ) *pOut_Hue = hue;
|
|
|
|
if ( pOut_Saturation ) *pOut_Saturation = saturation;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
HuesNotNear( int hue1, int hue2 )
|
|
|
|
{
|
|
|
|
int minimum, maximum;
|
|
|
|
BOOL boolNotNear;
|
|
|
|
int threshold = 30; // allowed difference in degrees
|
|
|
|
|
|
|
|
if ( hue1 == -1 ) hue1 = ( hue2 != -1 ) ? hue2 : 0; // hue is undefined (-1) when saturation is 0
|
|
|
|
if ( hue2 == -1 ) hue2 = hue1; // hue is undefined (-1) when saturation is 0
|
|
|
|
|
|
|
|
minimum = min( hue1, hue2 );
|
|
|
|
maximum = max( hue1, hue2 );
|
|
|
|
|
|
|
|
if ( maximum - minimum > 180 )
|
|
|
|
{
|
|
|
|
// Wrap the minimum around by 360 degrees
|
|
|
|
// to measure the shorter direction
|
|
|
|
maximum = minimum + 360;
|
|
|
|
minimum = maximum;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolNotNear = (maximum - minimum > threshold);
|
|
|
|
|
|
|
|
return boolNotNear;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
NearBlack( Color888_t *pColor888 )
|
|
|
|
{
|
|
|
|
return ( ColorBrightness( pColor888 ) < 15 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
DeriveMiddleColors( Color888_t *pColorHigh,
|
|
|
|
Color888_t *pOut_ColorMedHigh, // Return value
|
|
|
|
Color888_t *pOut_ColorMedLow, // Return value
|
|
|
|
Color888_t *pColorLow
|
|
|
|
)
|
|
|
|
{
|
|
|
|
pOut_ColorMedHigh->red = (unsigned char)(((unsigned int)pColorHigh->red * 5 + (unsigned int)pColorLow->red * 3) >> 3);
|
|
|
|
pOut_ColorMedHigh->green = (unsigned char)(((unsigned int)pColorHigh->green * 5 + (unsigned int)pColorLow->green * 3) >> 3);
|
|
|
|
pOut_ColorMedHigh->blue = (unsigned char)(((unsigned int)pColorHigh->blue * 5 + (unsigned int)pColorLow->blue * 3) >> 3);
|
|
|
|
|
|
|
|
pOut_ColorMedLow->red = (unsigned char)(((unsigned int)pColorHigh->red * 3 + (unsigned int)pColorLow->red * 5) >> 3);
|
|
|
|
pOut_ColorMedLow->green = (unsigned char)(((unsigned int)pColorHigh->green * 3 + (unsigned int)pColorLow->green * 5) >> 3);
|
|
|
|
pOut_ColorMedLow->blue = (unsigned char)(((unsigned int)pColorHigh->blue * 3 + (unsigned int)pColorLow->blue * 5) >> 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* DeriveMedLowFromHighAndMedHighColors():
|
|
|
|
* This function is used for the special case where we encode the
|
|
|
|
* high-luminance & medium-high-luminance colors instead of the
|
|
|
|
* high_luminance & low-luminance colors. It derives the
|
|
|
|
* medium-low luminance color. The low-luminance color is assumed
|
|
|
|
* to be black.
|
|
|
|
*
|
|
|
|
* Note: This is in it's own function for use by the decoder and the
|
|
|
|
* encoder when checking errors in index selection. Having this
|
|
|
|
* code in its own function makes it easy to make sure both
|
|
|
|
* places use the same exact algorithm.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
DeriveMedLowFromHighAndMedHighColors( Color888_t *pColorHigh,
|
|
|
|
Color888_t *pColorMedHigh,
|
|
|
|
Color888_t *pOut_ColorMedLow, // Return value
|
|
|
|
Color888_t *pOut_ColorLow // Return value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// Don't go negative!!!
|
|
|
|
|
|
|
|
pOut_ColorMedLow->red = (unsigned char)max((signed int)pColorMedHigh->red - (pColorHigh->red >> 2), 0);
|
|
|
|
pOut_ColorMedLow->green = (unsigned char)max((signed int)pColorMedHigh->green - (pColorHigh->green >> 2), 0);
|
|
|
|
pOut_ColorMedLow->blue = (unsigned char)max((signed int)pColorMedHigh->blue - (pColorHigh->blue >> 2), 0);
|
|
|
|
|
|
|
|
pOut_ColorLow->red = 0;
|
|
|
|
pOut_ColorLow->green = 0;
|
|
|
|
pOut_ColorLow->blue = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
SetDecoderColors( unsigned int colorLow565or1555, // IN: Encoded low color
|
|
|
|
unsigned int colorHigh565, // IN: Encoded high color
|
|
|
|
Color888_t (*pDecoderColors888)[4] // OUT: L, ML, MH, H colors to use
|
|
|
|
)
|
|
|
|
{
|
|
|
|
static int iColorLow = 0;
|
|
|
|
static int iColorMedLow = 1;
|
|
|
|
static int iColorMedHigh = 2;
|
|
|
|
static int iColorHigh = 3;
|
|
|
|
|
|
|
|
//----------------------------------------------------------
|
|
|
|
// Set colors based on encoder specified by ATITC SIGNATURE
|
|
|
|
//----------------------------------------------------------
|
|
|
|
|
|
|
|
BOOL boolBlackTrick = Color1555To888( colorLow565or1555, &(*pDecoderColors888)[ iColorLow ] );
|
|
|
|
Color565To888( colorHigh565, &(*pDecoderColors888)[ iColorHigh ] );
|
|
|
|
|
|
|
|
if ( boolBlackTrick )
|
|
|
|
{
|
|
|
|
(*pDecoderColors888)[ iColorMedHigh ] = (*pDecoderColors888)[ iColorLow ];
|
|
|
|
|
|
|
|
DeriveMedLowFromHighAndMedHighColors( &(*pDecoderColors888)[ iColorHigh ],
|
|
|
|
&(*pDecoderColors888)[ iColorMedHigh ],
|
|
|
|
&(*pDecoderColors888)[ iColorMedLow ],
|
|
|
|
&(*pDecoderColors888)[ iColorLow ] );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DeriveMiddleColors( &(*pDecoderColors888)[ iColorHigh ],
|
|
|
|
&(*pDecoderColors888)[ iColorMedHigh ],
|
|
|
|
&(*pDecoderColors888)[ iColorMedLow ],
|
|
|
|
&(*pDecoderColors888)[ iColorLow ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reconstruct a 4x4 block given two colors and a string of bits that
|
|
|
|
* indicate which of four colors to use to reconstruct each pixel. Two
|
|
|
|
* additional colors will be derived from the two passed in.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
atiDecodeRGBBlockATITC(
|
|
|
|
Color888_t (*pPixelsOut)[4][4],
|
|
|
|
unsigned int bitIndices,
|
|
|
|
unsigned int colorLow565or1555,
|
|
|
|
unsigned int colorHigh565
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int row, col;
|
|
|
|
Color888_t aColor888[ 4 ];
|
|
|
|
static int iColorLow = 0;
|
|
|
|
static int iColorMedLow = 1;
|
|
|
|
static int iColorMedHigh = 2;
|
|
|
|
static int iColorHigh = 3;
|
|
|
|
|
|
|
|
//--------------------
|
|
|
|
// Setup the colors
|
|
|
|
//--------------------
|
|
|
|
|
|
|
|
SetDecoderColors( colorLow565or1555, colorHigh565, &aColor888 );
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------
|
|
|
|
// Decode the block
|
|
|
|
//--------------------
|
|
|
|
|
|
|
|
for ( row = 0; row < 4; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
(*pPixelsOut)[row][col].red = aColor888[ bitIndices & 0x00000003 ].red;
|
|
|
|
(*pPixelsOut)[row][col].green = aColor888[ bitIndices & 0x00000003 ].green;
|
|
|
|
(*pPixelsOut)[row][col].blue = aColor888[ bitIndices & 0x00000003 ].blue;
|
|
|
|
|
|
|
|
bitIndices >>= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CalcRegionColors() - This function calculates the representative color for each of four
|
|
|
|
* luminance regions. Each pixel has 2 bits out of the bit indices to
|
|
|
|
* indicate which luminance region it belongs to. The indices are read
|
|
|
|
* from LSB to MSB.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
CalcRegionColors(
|
|
|
|
unsigned int bitIndices, // IN: Luma region indices for 4x4 block
|
|
|
|
Color888_t (*pPixels)[4][4], // IN: Color values for 4x4 block
|
|
|
|
Color888_t *pColorLow888, // OUT: Ave. color for Low region
|
|
|
|
Color888_t *pColorMedLow888, // OUT: Ave. color for MedLow region
|
|
|
|
Color888_t *pColorMedHigh888, // OUT: Ave. color for MedHigh region
|
|
|
|
Color888_t *pColorHigh888, // OUT: Ave. color for High region
|
|
|
|
int *pcLow, // OUT: Num colors in Low region
|
|
|
|
int *pcMedLow, // OUT: Num colors in MedLow region
|
|
|
|
int *pcMedHigh, // OUT: Num colors in MedHigh region
|
|
|
|
int *pcHigh // OUT: Num colors in High region
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int row, col;
|
|
|
|
int rAveHigh, gAveHigh, bAveHigh, cHigh;
|
|
|
|
int rAveMedHigh, gAveMedHigh, bAveMedHigh, cMedHigh;
|
|
|
|
int rAveMedLow, gAveMedLow, bAveMedLow, cMedLow;
|
|
|
|
int rAveLow, gAveLow, bAveLow, cLow;
|
|
|
|
|
|
|
|
//----------------------
|
|
|
|
// Zero counts & values
|
|
|
|
//----------------------
|
|
|
|
|
|
|
|
rAveHigh = gAveHigh = bAveHigh = cHigh = 0;
|
|
|
|
rAveMedHigh = gAveMedHigh = bAveMedHigh = cMedHigh = 0;
|
|
|
|
rAveMedLow = gAveMedLow = bAveMedLow = cMedLow = 0;
|
|
|
|
rAveLow = gAveLow = bAveLow = cLow = 0;
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// Sum up the colors of the pixels assigned to each region
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
for ( row = 0; row < 4; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
switch ( bitIndices & 0x00000003 )
|
|
|
|
{
|
|
|
|
case 0: rAveLow += (*pPixels)[row][col].red;
|
|
|
|
gAveLow += (*pPixels)[row][col].green;
|
|
|
|
bAveLow += (*pPixels)[row][col].blue;
|
|
|
|
cLow++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: rAveMedLow += (*pPixels)[row][col].red;
|
|
|
|
gAveMedLow += (*pPixels)[row][col].green;
|
|
|
|
bAveMedLow += (*pPixels)[row][col].blue;
|
|
|
|
cMedLow++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: rAveMedHigh += (*pPixels)[row][col].red;
|
|
|
|
gAveMedHigh += (*pPixels)[row][col].green;
|
|
|
|
bAveMedHigh += (*pPixels)[row][col].blue;
|
|
|
|
cMedHigh++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: rAveHigh += (*pPixels)[row][col].red;
|
|
|
|
gAveHigh += (*pPixels)[row][col].green;
|
|
|
|
bAveHigh += (*pPixels)[row][col].blue;
|
|
|
|
cHigh++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bitIndices >>= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------
|
|
|
|
// Compute the center of gravity of each luminance region
|
|
|
|
//--------------------------------------------------------
|
|
|
|
|
|
|
|
if ( cLow ) { rAveLow /= cLow; gAveLow /= cLow; bAveLow /= cLow; }
|
|
|
|
if ( cMedLow ) { rAveMedLow /= cMedLow; gAveMedLow /= cMedLow; bAveMedLow /= cMedLow; }
|
|
|
|
if ( cMedHigh ) { rAveMedHigh /= cMedHigh; gAveMedHigh /= cMedHigh; bAveMedHigh /= cMedHigh; }
|
|
|
|
if ( cHigh ) { rAveHigh /= cHigh; gAveHigh /= cHigh; bAveHigh /= cHigh; }
|
|
|
|
|
|
|
|
//-------------------------------------------------
|
|
|
|
// Return the representative color for each region
|
|
|
|
//-------------------------------------------------
|
|
|
|
|
|
|
|
pColorLow888->red = (unsigned char)rAveLow;
|
|
|
|
pColorLow888->green = (unsigned char)gAveLow;
|
|
|
|
pColorLow888->blue = (unsigned char)bAveLow;
|
|
|
|
|
|
|
|
pColorMedLow888->red = (unsigned char)rAveMedLow;
|
|
|
|
pColorMedLow888->green = (unsigned char)gAveMedLow;
|
|
|
|
pColorMedLow888->blue = (unsigned char)bAveMedLow;
|
|
|
|
|
|
|
|
pColorMedHigh888->red = (unsigned char)rAveMedHigh;
|
|
|
|
pColorMedHigh888->green = (unsigned char)gAveMedHigh;
|
|
|
|
pColorMedHigh888->blue = (unsigned char)bAveMedHigh;
|
|
|
|
|
|
|
|
pColorHigh888->red = (unsigned char)rAveHigh;
|
|
|
|
pColorHigh888->green = (unsigned char)gAveHigh;
|
|
|
|
pColorHigh888->blue = (unsigned char)bAveHigh;
|
|
|
|
|
|
|
|
//-------------------------------------------
|
|
|
|
// Return the count of pixels in each region
|
|
|
|
//-------------------------------------------
|
|
|
|
|
|
|
|
*pcLow = cLow;
|
|
|
|
*pcMedLow = cMedLow;
|
|
|
|
*pcMedHigh = cMedHigh;
|
|
|
|
*pcHigh = cHigh;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CalcBlockMSE() - This function decodes a block using the specified fields
|
|
|
|
* "bitIndices", "colorLow565", and "colorHigh565". The
|
|
|
|
* result is compared against the original block passed in
|
|
|
|
* pPixels[][], and the mean squared error is returned.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static MSE_t
|
|
|
|
CalcBlockMSE(
|
|
|
|
unsigned int bitIndices, // IN: Luma region indices for 4x4 block
|
|
|
|
unsigned int colorLow565or1555, // IN: Low luminance color encoded
|
|
|
|
unsigned int colorHigh565, // IN: High luminance color encoded
|
|
|
|
Color888_t (*pPixelsOrig)[4][4] // IN: Color values for original 4x4 block
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Color888_t pixelsDecoded[4][4];
|
|
|
|
MSE_t MSE = MSE_ZERO;
|
|
|
|
int row, col;
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Decode the pixels using bitIndices, colorLow565, and colorHigh565
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
|
|
atiDecodeRGBBlockATITC(
|
|
|
|
&pixelsDecoded, // place for decoded pixels
|
|
|
|
bitIndices,
|
|
|
|
colorLow565or1555,
|
|
|
|
colorHigh565 );
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
// Compare the reconstructed pixels against the original pixels
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
for ( row = 0; row < 4; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
MSE += ErrSquared( &(*pPixelsOrig)[row][col], &pixelsDecoded[row][col] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return MSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Given a 4x4 block of luma values and 3 luma region
|
|
|
|
* boundaries, set an array of 2-bit indicies to specify
|
|
|
|
* which region each value belongs in.
|
|
|
|
*/
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
CollatePixelsIntoRegions(
|
|
|
|
unsigned int (*pY)[4][4],
|
|
|
|
unsigned int medLowLumaStart,
|
|
|
|
unsigned int medHighLumaStart,
|
|
|
|
unsigned int highLumaStart
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int row, col;
|
|
|
|
unsigned int luma;
|
|
|
|
unsigned int bitMask = 0x00000003; // Array of 16 2-bit region luma indices
|
|
|
|
unsigned int bitIndices = 0;
|
|
|
|
|
|
|
|
for ( row = 0; row < 4; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
luma = (*pY)[row][col];
|
|
|
|
|
|
|
|
if ( luma >= highLumaStart )
|
|
|
|
{
|
|
|
|
// High luminance pixel
|
|
|
|
bitIndices |= (bitMask & 0xFFFFFFFF); // set bits to 11b
|
|
|
|
}
|
|
|
|
else if ( luma > medHighLumaStart )
|
|
|
|
{
|
|
|
|
// Medium-high luminance pixel
|
|
|
|
bitIndices |= (bitMask & 0xAAAAAAAA); // set bits to 10b
|
|
|
|
}
|
|
|
|
else if ( luma > medLowLumaStart )
|
|
|
|
{
|
|
|
|
// Medium-low luminance pixel
|
|
|
|
bitIndices |= (bitMask & 0x55555555); // set bits to 01b
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Low luminance pixel
|
|
|
|
// set bits to 00b
|
|
|
|
}
|
|
|
|
|
|
|
|
bitMask <<= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return bitIndices;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ApplyBlackTrickIfHelpful() - indicates if black trick should be used. Also moves
|
|
|
|
* med-low region pixels & color to med-high region if
|
|
|
|
* it's empty.
|
|
|
|
*/
|
|
|
|
static BOOL
|
|
|
|
ApplyBlackTrickIfHelpful(
|
|
|
|
unsigned int *pBitIndices, // IN/OUT: Luma region indices for 4x4 block
|
|
|
|
Color888_t *pColorLow888, // IN/OUT: Ave. color for Low region
|
|
|
|
Color888_t *pColorMedLow888, // IN/OUT: Ave. color for MedLow region
|
|
|
|
Color888_t *pColorMedHigh888, // IN/OUT: Ave. color for MedHigh region
|
|
|
|
Color888_t *pColorHigh888, // IN/OUT: Ave. color for High region
|
|
|
|
int *pcLow, // IN/OUT: Num colors in Low region
|
|
|
|
int *pcMedLow, // IN/OUT: Num colors in MedLow region
|
|
|
|
int *pcMedHigh // IN/OUT: Num colors in MedHigh region
|
|
|
|
)
|
|
|
|
{
|
|
|
|
BOOL boolUseBlackTrick = FALSE;
|
|
|
|
int hueHigh, hueMedHigh, hueMedLow;
|
|
|
|
int saturationHigh, saturationMedHigh, saturationMedLow;
|
|
|
|
unsigned int bitMask = 0x00000003; // Mask to indicate luminance (low, med, high) for pixel
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
|
|
// Determine if the black trick can help with this 4x4 block
|
|
|
|
//-----------------------------------------------------------
|
|
|
|
|
|
|
|
if ( *pcLow && NearBlack( pColorLow888 ) && ColorBrightness( pColorHigh888 ) > 55 )
|
|
|
|
{
|
|
|
|
ColorHueAndSaturation( pColorHigh888, &hueHigh, &saturationHigh );
|
|
|
|
|
|
|
|
// Set defaults in case MedHigh or MedLow colors don't exist
|
|
|
|
hueMedHigh = hueMedLow = hueHigh;
|
|
|
|
saturationMedHigh = saturationMedLow = saturationHigh;
|
|
|
|
|
|
|
|
if ( *pcMedHigh > 0 )
|
|
|
|
ColorHueAndSaturation( pColorMedHigh888, &hueMedHigh, &saturationMedHigh );
|
|
|
|
|
|
|
|
if ( *pcMedLow > 0 )
|
|
|
|
ColorHueAndSaturation( pColorMedLow888, &hueMedLow, &saturationMedLow );
|
|
|
|
|
|
|
|
if ( HuesNotNear( hueHigh, hueMedHigh ) ||
|
|
|
|
HuesNotNear( hueHigh, hueMedLow ) ||
|
|
|
|
( *pcMedHigh && ((saturationMedHigh > saturationHigh * 2) || (saturationMedHigh > 70)) ) ||
|
|
|
|
( *pcMedLow && ((saturationMedLow > saturationHigh * 2) || (saturationMedLow > 70)) )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//-------------------------------
|
|
|
|
// We should use the black trick
|
|
|
|
//-------------------------------
|
|
|
|
|
|
|
|
boolUseBlackTrick = TRUE;
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// If the medium-high luminance region is empty, move everything
|
|
|
|
// from the medium-low luminance region into the medium-high region.
|
|
|
|
// This improves image quality because the medium-high color is
|
|
|
|
// encoded while the medium-low color is derived.
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
|
|
if ( *pcMedHigh == 0 )
|
|
|
|
{
|
|
|
|
// Since there are no texels in the medium-high luminance region, use this
|
|
|
|
// slot for the medium-low luminance color. That way we can get the exact
|
|
|
|
// color we want.
|
|
|
|
|
|
|
|
*pColorMedHigh888 = *pColorMedLow888;
|
|
|
|
*pcMedHigh = *pcMedLow;
|
|
|
|
|
|
|
|
pColorMedLow888->red = 0;
|
|
|
|
pColorMedLow888->green = 0;
|
|
|
|
pColorMedLow888->blue = 0;
|
|
|
|
*pcMedLow = 0;
|
|
|
|
|
|
|
|
// Change all '01b' indices to '10b'
|
|
|
|
while ( bitMask )
|
|
|
|
{
|
|
|
|
if ( (*pBitIndices & bitMask) == (0x55555555 & bitMask) )
|
|
|
|
{
|
|
|
|
*pBitIndices &= (~bitMask); // Clear the '01b' index
|
|
|
|
*pBitIndices |= (bitMask & 0xAAAAAAAA); // Set the '10b' index
|
|
|
|
}
|
|
|
|
bitMask <<= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return boolUseBlackTrick;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
CheckPixelRegionAssignment(
|
|
|
|
Color888_t (*pPixels)[4][4], // IN: Original pixels
|
|
|
|
unsigned int *pBitIndices, // IN/OUT: Luma region indices for 4x4 block
|
|
|
|
Color888_t *pColorLow888, // IN: low-luminance color
|
|
|
|
Color888_t *pColorHigh888, // IN: high-luminance color
|
|
|
|
BOOL boolBlackTrick // IN:
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int row, col;
|
|
|
|
Color888_t aColor888[ 4 ];
|
|
|
|
Color888_t colorCurrent;
|
|
|
|
static int iColorLow = 0;
|
|
|
|
static int iColorMedLow = 1;
|
|
|
|
static int iColorMedHigh = 2;
|
|
|
|
static int iColorHigh = 3;
|
|
|
|
unsigned int bitMask = 0x00000003; // Mask to indicate luminance (low, med, high) for pixel
|
|
|
|
unsigned int index_low;
|
|
|
|
MSE_t err_squared, err_squared_low;
|
|
|
|
BOOL boolSomePixelsMoved = FALSE;
|
|
|
|
unsigned int bitIndices = *pBitIndices;
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------
|
|
|
|
// Setup the colors
|
|
|
|
//--------------------
|
|
|
|
|
|
|
|
SetDecoderColors( Color888To1555( pColorLow888, boolBlackTrick ),
|
|
|
|
Color888To565( pColorHigh888 ),
|
|
|
|
&aColor888 );
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
// Compare each pixel against the color associated with each region
|
|
|
|
// to make sure that it's placed in the region that results in the
|
|
|
|
// color that's closest to the original.
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
|
|
|
|
for ( row = 0; row < 4; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
colorCurrent.red = (*pPixels)[row][col].red;
|
|
|
|
colorCurrent.green = (*pPixels)[row][col].green;
|
|
|
|
colorCurrent.blue = (*pPixels)[row][col].blue;
|
|
|
|
|
|
|
|
// --- Calc error w.r.t. low color ---
|
|
|
|
|
|
|
|
err_squared_low = ErrSquared( &colorCurrent, &aColor888[ iColorLow ] );
|
|
|
|
index_low = 0x00000000; // default to low color
|
|
|
|
|
|
|
|
// --- Calc error w.r.t. med-low color ---
|
|
|
|
|
|
|
|
err_squared = ErrSquared( &colorCurrent, &aColor888[ iColorMedLow ] );
|
|
|
|
if ( err_squared < err_squared_low )
|
|
|
|
{
|
|
|
|
err_squared_low = err_squared;
|
|
|
|
index_low = 0x55555555;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- Calc error w.r.t. med-low color ---
|
|
|
|
|
|
|
|
err_squared = ErrSquared( &colorCurrent, &aColor888[ iColorMedHigh ] );
|
|
|
|
if ( err_squared < err_squared_low )
|
|
|
|
{
|
|
|
|
err_squared_low = err_squared;
|
|
|
|
index_low = 0xAAAAAAAA;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- Calc error w.r.t. high color ---
|
|
|
|
|
|
|
|
err_squared = ErrSquared( &colorCurrent, &aColor888[ iColorHigh ] );
|
|
|
|
if ( err_squared < err_squared_low )
|
|
|
|
{
|
|
|
|
err_squared_low = err_squared;
|
|
|
|
index_low = 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Reset index for pixel if the one we set based on luminance isn't the nearest
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
if ( (bitIndices & bitMask) != (index_low & bitMask) )
|
|
|
|
{
|
|
|
|
bitIndices &= (~bitMask);
|
|
|
|
bitIndices |= (bitMask & index_low);
|
|
|
|
boolSomePixelsMoved = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bitMask <<= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Make sure we still have pixels in the high-luminance & low-luminance
|
|
|
|
// regions because the two colors we encode come from those two regions.
|
|
|
|
// Note: if black trick is in use, we don't require any low-luminance
|
|
|
|
// region pixels.
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
if ( boolSomePixelsMoved )
|
|
|
|
{
|
|
|
|
int i, index;
|
|
|
|
int count[4] = {0, 0, 0, 0};
|
|
|
|
unsigned int bitIndicesTemp = bitIndices;
|
|
|
|
|
|
|
|
// Count how many pixels are in each region
|
|
|
|
|
|
|
|
for ( i = 0; i < 16; i++ )
|
|
|
|
{
|
|
|
|
index = bitIndicesTemp & 0x00000003;
|
|
|
|
count[index]++;
|
|
|
|
bitIndicesTemp >>= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (count[iColorHigh] && count[iColorLow]) ||
|
|
|
|
(count[iColorHigh] == 16) ||
|
|
|
|
(count[iColorHigh] && boolBlackTrick) )
|
|
|
|
*pBitIndices = bitIndices; // We can apply the changes
|
|
|
|
else
|
|
|
|
boolSomePixelsMoved = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return boolSomePixelsMoved;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* (1)
|
|
|
|
* Given a reference to a 4x4 block of RGB pixels, create a 4x4 matrix of
|
|
|
|
* 2-bit values that indicate whether the pixel in the corresponding position
|
|
|
|
* is in the lower region, medium-low region, medium-high region, or upper region
|
|
|
|
* of luminance for the block.
|
|
|
|
*
|
|
|
|
* Return the 4x4 matrix of bits as an unsigned integer scalar.
|
|
|
|
*
|
|
|
|
* (2)
|
|
|
|
* Calculate the average color for each of the four luminance levels and determine
|
|
|
|
* two reference colors to be returned to the caller along with a set of two-bit
|
|
|
|
* indices to these colors. Each pixel in the block has two of these bits to index
|
|
|
|
* a color. Indices 0 & 3 refer to one of the colors returned, while indices
|
|
|
|
* 1 & 2 refer to one of two colors derived from the two returned.
|
|
|
|
*/
|
|
|
|
unsigned int
|
|
|
|
atiEncodeRGBBlockATITC(
|
|
|
|
Color888_t (*pPixels)[4][4],
|
|
|
|
unsigned int *pColorLow565or1555Ret, // Return value
|
|
|
|
unsigned int *pColorHigh565Ret // Return value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int row, col;
|
|
|
|
int cLow, cMedLow, cMedHigh, cHigh = 0; // Pixels in each region
|
|
|
|
Color888_t colorLow888, colorMedLow888, colorMedHigh888, colorHigh888; // Color for each region
|
|
|
|
unsigned int medLowLumaStart, medHighLumaStart, highLumaStart;
|
|
|
|
unsigned int medLowLumaStartPrev, highLumaStartPrev;
|
|
|
|
unsigned int luma;
|
|
|
|
unsigned int Y[4][4]; // 4x4 matrix of luminance for the 4x4 block
|
|
|
|
unsigned int Y_Sorted[17];
|
|
|
|
unsigned int numYSorted;
|
|
|
|
unsigned int i, j;
|
|
|
|
unsigned int bitIndices = 0;
|
|
|
|
BOOL boolBlackTrick;
|
|
|
|
unsigned int colorLow565or1555, colorHigh565;
|
|
|
|
MSE_t blockMSE;
|
|
|
|
MSE_t best_BlockMSE = MSE_HIGHEST;// Begin with highest possible value
|
|
|
|
unsigned int best_BitIndices = 0;
|
|
|
|
Color888_t best_ColorLow888 = {0,0,0}, best_ColorMedLow888 = {0,0,0}, best_ColorMedHigh888 = {0,0,0}, best_ColorHigh888 = {0,0,0};
|
|
|
|
BOOL best_boolBlackTrick = FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Create a 4x4 block of luma values, and keep a sorted list of the values
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Y_Sorted[0] = 256; // Greater than maximum possible value as sentinel
|
|
|
|
numYSorted = 0; // Num values already inserted
|
|
|
|
|
|
|
|
for ( row = 0; row < 4; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
luma = LUMINANCE( (*pPixels)[row][col].red,
|
|
|
|
(*pPixels)[row][col].green,
|
|
|
|
(*pPixels)[row][col].blue );
|
|
|
|
|
|
|
|
// Insert into 4x4 block
|
|
|
|
Y[row][col] = luma;
|
|
|
|
|
|
|
|
// Insert into a sorted list
|
|
|
|
i = 0;
|
|
|
|
while ( luma >= Y_Sorted[i] ) i++; // Find insertion position
|
|
|
|
|
|
|
|
for ( j = numYSorted+1; j > i; j-- ) // Shift elements back to make room
|
|
|
|
Y_Sorted[j] = Y_Sorted[j-1];
|
|
|
|
|
|
|
|
Y_Sorted[i] = luma;
|
|
|
|
numYSorted++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------
|
|
|
|
// Test various luminance region boundaries
|
|
|
|
//------------------------------------------
|
|
|
|
|
|
|
|
highLumaStartPrev = 256; // Greater than maximum possible
|
|
|
|
for ( i = 15; i > 0; i-- )
|
|
|
|
{
|
|
|
|
highLumaStart = Y_Sorted[i];
|
|
|
|
if ( highLumaStart == highLumaStartPrev ) continue; // Skip duplicate values
|
|
|
|
|
|
|
|
medLowLumaStartPrev = 256; // Greater than maximum possible
|
|
|
|
for ( j = 0; j < i; j++ )
|
|
|
|
{
|
|
|
|
medLowLumaStart = Y_Sorted[j];
|
|
|
|
if ( medLowLumaStart == medLowLumaStartPrev ) continue; // Skip duplicate values
|
|
|
|
|
|
|
|
medHighLumaStart = Y_Sorted[(i + j) >> 1];
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// Create an array of 16 2-bit indices that specify which
|
|
|
|
// luminance region each pixels belongs to
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bitIndices = CollatePixelsIntoRegions( &Y, // 4x4 block of luma values
|
|
|
|
medLowLumaStart,
|
|
|
|
medHighLumaStart,
|
|
|
|
highLumaStart );
|
|
|
|
|
|
|
|
//----------------------------------------------------
|
|
|
|
// Calculate the representative color for each region
|
|
|
|
//----------------------------------------------------
|
|
|
|
|
|
|
|
CalcRegionColors( bitIndices,
|
|
|
|
pPixels,
|
|
|
|
&colorLow888,
|
|
|
|
&colorMedLow888,
|
|
|
|
&colorMedHigh888,
|
|
|
|
&colorHigh888,
|
|
|
|
&cLow,
|
|
|
|
&cMedLow,
|
|
|
|
&cMedHigh,
|
|
|
|
&cHigh );
|
|
|
|
|
|
|
|
//--------------------------------------------
|
|
|
|
// Determine if we should use the black trick
|
|
|
|
//--------------------------------------------
|
|
|
|
|
|
|
|
boolBlackTrick = ApplyBlackTrickIfHelpful( &bitIndices,
|
|
|
|
&colorLow888,
|
|
|
|
&colorMedLow888,
|
|
|
|
&colorMedHigh888,
|
|
|
|
&colorHigh888,
|
|
|
|
&cLow,
|
|
|
|
&cMedLow,
|
|
|
|
&cMedHigh );
|
|
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
// Calculate the MSE based on the current luma region boundaries
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
|
|
|
|
if ( boolBlackTrick )
|
|
|
|
{
|
|
|
|
colorLow565or1555 = Color888To1555( &colorMedHigh888, boolBlackTrick );
|
|
|
|
colorHigh565 = Color888To565( &colorHigh888 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
colorLow565or1555 = Color888To1555( &colorLow888, boolBlackTrick );
|
|
|
|
colorHigh565 = Color888To565( &colorHigh888 );
|
|
|
|
}
|
|
|
|
|
|
|
|
blockMSE = CalcBlockMSE( bitIndices, // Bit indices to specify luma region per pixel
|
|
|
|
colorLow565or1555, // Low luma region color
|
|
|
|
colorHigh565, // High luma region color
|
|
|
|
pPixels ); // Original pixel values
|
|
|
|
|
|
|
|
//---------------------------------------------------
|
|
|
|
// Keep track of the lowest block mean squared error
|
|
|
|
// and the associated encoding information
|
|
|
|
//---------------------------------------------------
|
|
|
|
|
|
|
|
if ( blockMSE < best_BlockMSE )
|
|
|
|
{
|
|
|
|
best_BlockMSE = blockMSE;
|
|
|
|
|
|
|
|
best_BitIndices = bitIndices;
|
|
|
|
best_ColorLow888 = colorLow888;
|
|
|
|
best_ColorMedLow888 = colorMedLow888;
|
|
|
|
best_ColorMedHigh888 = colorMedHigh888;
|
|
|
|
best_ColorHigh888 = colorHigh888;
|
|
|
|
best_boolBlackTrick = boolBlackTrick;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------
|
|
|
|
// Use the values that produced the lowest block MSE
|
|
|
|
//---------------------------------------------------
|
|
|
|
|
|
|
|
bitIndices = best_BitIndices;
|
|
|
|
colorLow888 = best_ColorLow888;
|
|
|
|
colorMedLow888 = best_ColorMedLow888;
|
|
|
|
colorMedHigh888 = best_ColorMedHigh888;
|
|
|
|
colorHigh888 = best_ColorHigh888;
|
|
|
|
boolBlackTrick = best_boolBlackTrick;
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
// If we're using the black trick, change which colors we encode
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
|
|
|
|
if ( boolBlackTrick )
|
|
|
|
{
|
|
|
|
colorLow888 = colorMedHigh888;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------
|
|
|
|
// Make sure pixels are assigned to the best region
|
|
|
|
//--------------------------------------------------
|
|
|
|
|
|
|
|
if ( CheckPixelRegionAssignment( pPixels, &bitIndices, &colorLow888, &colorHigh888,
|
|
|
|
boolBlackTrick ) )
|
|
|
|
{
|
|
|
|
//------------------------------------------------------
|
|
|
|
// Recalculate the representative color for each region
|
|
|
|
//------------------------------------------------------
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
CalcRegionColors( bitIndices,
|
|
|
|
pPixels,
|
|
|
|
&colorLow888,
|
|
|
|
&colorMedLow888,
|
|
|
|
&colorMedHigh888,
|
|
|
|
&colorHigh888,
|
|
|
|
&cLow,
|
|
|
|
&cMedLow,
|
|
|
|
&cMedHigh,
|
|
|
|
&cHigh );
|
|
|
|
|
|
|
|
//--------------------------------------------
|
|
|
|
// Determine if we should use the black trick
|
|
|
|
//--------------------------------------------
|
|
|
|
|
|
|
|
boolBlackTrick = ApplyBlackTrickIfHelpful( &bitIndices,
|
|
|
|
&colorLow888,
|
|
|
|
&colorMedLow888,
|
|
|
|
&colorMedHigh888,
|
|
|
|
&colorHigh888,
|
|
|
|
&cLow,
|
|
|
|
&cMedLow,
|
|
|
|
&cMedHigh );
|
|
|
|
|
|
|
|
// WARNING: We have problems if boolBlackTrick == TRUE here but FALSE after the
|
|
|
|
// call to ApplyBlackTrickIfHelpful(). That's because the MSE up to
|
|
|
|
// this point was based on the color derivations based on the black trick.
|
|
|
|
|
|
|
|
if ( boolBlackTrick != best_boolBlackTrick )
|
|
|
|
{
|
|
|
|
// Roll back the recalculation of region colors
|
|
|
|
bitIndices = best_BitIndices;
|
|
|
|
colorLow888 = best_ColorLow888;
|
|
|
|
colorMedLow888 = best_ColorMedLow888;
|
|
|
|
colorMedHigh888 = best_ColorMedHigh888;
|
|
|
|
colorHigh888 = best_ColorHigh888;
|
|
|
|
boolBlackTrick = best_boolBlackTrick;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
// If we're using the black trick, change which colors we encode
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
|
|
|
|
if ( boolBlackTrick )
|
|
|
|
{
|
|
|
|
colorLow888 = colorMedHigh888;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------
|
|
|
|
// Return the two colors to encode
|
|
|
|
//---------------------------------
|
|
|
|
|
|
|
|
*pColorLow565or1555Ret = Color888To1555( &colorLow888, boolBlackTrick );
|
|
|
|
*pColorHigh565Ret = Color888To565( &colorHigh888 );
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------
|
|
|
|
// Return a string of bits that indicate which of the two
|
|
|
|
// (or derivations of the two) encoded colors to use for
|
|
|
|
// each pixel.
|
|
|
|
//--------------------------------------------------------
|
|
|
|
|
|
|
|
//assert( cHigh != 0 );
|
|
|
|
return bitIndices;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* atiEncodeAlphaBlockATITCA4() - Source has already been expanded to 8-bit format
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
atiEncodeAlphaBlockATITCA4( unsigned char (*pSrcAlpha)[4][4], unsigned int (*pEncodedAlpha)[2] )
|
|
|
|
{
|
|
|
|
int row, col;
|
|
|
|
|
|
|
|
(*pEncodedAlpha)[0] = 0;
|
|
|
|
(*pEncodedAlpha)[1] = 0;
|
|
|
|
|
|
|
|
//--------------------------------------------------
|
|
|
|
// Fill in 1st 32-bit DWORD with 4-bit alpha values
|
|
|
|
//--------------------------------------------------
|
|
|
|
for ( row = 0; row < 2; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
(*pEncodedAlpha)[0] >>= 4;
|
|
|
|
(*pEncodedAlpha)[0] |= (unsigned int)((*pSrcAlpha)[row][col] & 0xF0) << 24; // Take just the 4 high bits
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------
|
|
|
|
// Fill in 2nd 32-bit DWORD with 4-bit alpha values
|
|
|
|
//--------------------------------------------------
|
|
|
|
for ( row = 2; row < 4; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
(*pEncodedAlpha)[1] >>= 4;
|
|
|
|
(*pEncodedAlpha)[1] |= (unsigned int)((*pSrcAlpha)[row][col] & 0xF0) << 24; // Take just the 4 high bits
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* atiDecodeAlphaBlockATITCA4() - Input is 4 bits of alpha per pixel; output is 8 bits of alpha per pixel
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
atiDecodeAlphaBlockATITCA4( unsigned char (*pAlphaOut)[4][4],
|
|
|
|
unsigned char *pEncodedData
|
|
|
|
)
|
|
|
|
{
|
|
|
|
unsigned int encodedAlpha = *((unsigned int*)pEncodedData);
|
|
|
|
unsigned int alpha;
|
|
|
|
int row, col;
|
|
|
|
|
|
|
|
//-----------------------------------------------
|
|
|
|
// Decode the Alpha portion of the 1st two rows
|
|
|
|
//-----------------------------------------------
|
|
|
|
|
|
|
|
for ( row = 0; row < 2; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
alpha = encodedAlpha & 0x0000000F;
|
|
|
|
alpha = alpha | (alpha << 4);
|
|
|
|
|
|
|
|
(*pAlphaOut)[row][col] = (unsigned char)alpha;
|
|
|
|
|
|
|
|
encodedAlpha >>= 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------
|
|
|
|
// Decode the Alpha portion of the last two rows
|
|
|
|
//------------------------------------------------
|
|
|
|
|
|
|
|
encodedAlpha = *((unsigned int*)pEncodedData + 1);
|
|
|
|
|
|
|
|
for ( row = 2; row < 4; row++ )
|
|
|
|
{
|
|
|
|
for ( col = 0; col < 4; col++ )
|
|
|
|
{
|
|
|
|
alpha = encodedAlpha & 0x0000000F;
|
|
|
|
alpha = alpha | (alpha << 4);
|
|
|
|
|
|
|
|
(*pAlphaOut)[row][col] = (unsigned char)alpha;
|
|
|
|
|
|
|
|
encodedAlpha >>= 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|