📄 surfaceformat.cpp
字号:
#include <gr/SurfaceFormat.h>
#include <assert.h>
#include <config.h>
namespace gr
{
const char* const FORMAT_NAMES[] =
{
/** The surface format is unknown. */
"UNKNOWN",
/** 24-bit RGB pixel format. */
"R8G8B8",
/** 24-bit RGB pixel format. */
"B8G8R8",
/** 32-bit RGB pixel format with alpha. */
"A8R8G8B8",
/** 32-bit RGB pixel format where 8 bits are reserved for each color. */
"X8R8G8B8",
/** 32-bit RGB pixel format where 8 bits are reserved for each color. */
"X8B8G8R8",
/** 32-bit RGB pixel format with alpha. */
"A8B8G8R8",
/** 16-bit RGB pixel format. (PS2) */
"R5G6B5",
/** 16-bit RGB pixel format. */
"R5G5B5",
/** 4-bit palettized pixel format. (PC/PS2) */
"P4",
/** 8-bit palettized pixel format. (PC/PS2) */
"P8",
/** 16-bit pixel format where 5 bits are reserved for color and 1 bit is reserved for transparency. */
"A1R5G5B5",
/** 16-bit RGB pixel format where 4 bits are reserved for each color. */
"X4R4G4B4",
/** 16-bit RGB pixel format. */
"A4R4G4B4",
/** 16-bit pixel format where 5 bits are reserved for color and 1 bit is reserved for transparency. */
"A1B5G5R5",
/** 8-bit RGB texture format. (PS2) */
"R3G3B2",
/** 8-bit RGB texture format. */
"R3G2B3",
/** 8-bit alpha-only. */
"A8",
/** 16-bit RGB pixel format with alpha. */
"A8R3G3B2",
/** 16-bit RGB pixel format with alpha. */
"A8R3G2B3",
/** "32", depth using 24 bits and stencil 8 bits */
"D24S8",
};
/**
* Descriptions of surface formats:
* {format, bitcount, red mask, green mask, blue mask, alpha mask}.
*/
static const uint32_t FORMATDESC[][6] =
{
{SurfaceFormat::SURFACE_UNKNOWN , 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{SurfaceFormat::SURFACE_R8G8B8 , 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
{SurfaceFormat::SURFACE_B8G8R8 , 24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000},
{SurfaceFormat::SURFACE_A8R8G8B8 , 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
{SurfaceFormat::SURFACE_X8R8G8B8 , 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
{SurfaceFormat::SURFACE_X8B8G8R8 , 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000},
{SurfaceFormat::SURFACE_A8B8G8R8 , 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
{SurfaceFormat::SURFACE_R5G6B5 , 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000},
{SurfaceFormat::SURFACE_R5G5B5 , 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00000000},
{SurfaceFormat::SURFACE_P4 , 4, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{SurfaceFormat::SURFACE_P8 , 8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{SurfaceFormat::SURFACE_A1R5G5B5 , 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000},
{SurfaceFormat::SURFACE_X4R4G4B4 , 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x00000000},
{SurfaceFormat::SURFACE_A4R4G4B4 , 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000},
{SurfaceFormat::SURFACE_A1B5G5R5 , 16, 0x0000001f, 0x000003e0, 0x00007c00, 0x00008000},
{SurfaceFormat::SURFACE_R3G3B2 , 8, 0x000000e0, 0x0000001c, 0x00000003, 0x00000000},
{SurfaceFormat::SURFACE_R3G2B3 , 8, 0x000000e0, 0x00000018, 0x00000007, 0x00000000},
{SurfaceFormat::SURFACE_A8 , 8, 0x00000000, 0x00000000, 0x00000000, 0x000000ff},
{SurfaceFormat::SURFACE_A8R3G3B2 , 16, 0x000000e0, 0x0000001c, 0x00000003, 0x0000ff00},
{SurfaceFormat::SURFACE_A8R3G2B3 , 16, 0x000000e0, 0x00000018, 0x00000007, 0x0000ff00},
};
/** Number of supported surface formats. */
static const int FORMATS = sizeof(FORMATDESC)/sizeof(FORMATDESC[0]);
/**
* Returns left zero bit count before first non-zero bit.
*/
static inline int maskToShift( uint32_t mask )
{
int count = 0;
uint32_t testBit = 1;
if ( 0 == mask )
return 32;
while ( 0 == (mask & testBit) )
{
++count;
testBit += testBit;
}
return count;
}
/**
* Returns number of non-zero bits in the dword.
*/
static inline int countBits( uint32_t mask )
{
int count = 0;
uint32_t testBit = 1;
while ( 0 != testBit )
{
if ( 0 != (mask&testBit) )
++count;
testBit += testBit;
}
return count;
}
SurfaceFormat::SurfaceFormat() :
m_type( SurfaceFormat::SURFACE_UNKNOWN )
{
assert( SURFACE_LAST == FORMATS );
}
SurfaceFormat::SurfaceFormat( SurfaceFormatType type ) :
m_type( type )
{
assert( (SurfaceFormatType)FORMATDESC[type][0] == type );
assert( SURFACE_LAST == FORMATS );
}
SurfaceFormat::SurfaceFormat( int bitCount, uint32_t redMask, uint32_t greenMask, uint32_t blueMask, uint32_t alphaMask )
{
m_type = SurfaceFormat::SURFACE_UNKNOWN;
for ( int i = 0 ; i < FORMATS ; ++i )
{
if ( FORMATDESC[i][1] == (uint32_t)bitCount &&
FORMATDESC[i][2] == (uint32_t)redMask &&
FORMATDESC[i][3] == (uint32_t)greenMask &&
FORMATDESC[i][4] == (uint32_t)blueMask &&
FORMATDESC[i][5] == (uint32_t)alphaMask )
{
m_type = (SurfaceFormat::SurfaceFormatType)FORMATDESC[i][0];
}
}
}
SurfaceFormat::SurfaceFormatType SurfaceFormat::type() const
{
return m_type;
}
int SurfaceFormat::bitsPerPixel() const
{
return (int)FORMATDESC[m_type][1];
}
int SurfaceFormat::paletteEntries() const
{
if ( SURFACE_P8 == m_type )
return 256;
else if ( SURFACE_P4 == m_type )
return 16;
else
return 0;
}
void SurfaceFormat::copyPixels( void* dst, const SurfaceFormat& dstpalfmt, const void* dstpal,
const SurfaceFormat& srcfmt, const void* src, const SurfaceFormat& srcpalfmt, const void* srcpal,
int pixels ) const
{
assert( srcfmt.m_type != SURFACE_UNKNOWN );
assert( srcpalfmt.m_type != SURFACE_P4 && srcpalfmt.m_type != SURFACE_P8 );
assert( dstpalfmt.m_type != SURFACE_P4 && dstpalfmt.m_type != SURFACE_P8 );
assert( !srcpalfmt.palettized() );
assert( !srcpalfmt.palettized() );
assert( srcpalfmt.m_type == SURFACE_UNKNOWN || srcpal );
assert( dstpalfmt.m_type == SURFACE_UNKNOWN || dstpal );
if ( !srcfmt.palettized() )
srcpal = 0;
if ( !palettized() )
dstpal = 0;
const uint8_t* srcbytes = reinterpret_cast<const uint8_t*>( src );
const uint8_t* srcpalbytes = reinterpret_cast<const uint8_t*>( srcpal );
const int srcpalentries = srcfmt.paletteEntries();
const int srcbitcount = FORMATDESC[srcfmt.m_type][1];
int srcsubpix = 0;
const int srcbitoffs = (8-srcbitcount) & 7;
const uint32_t* srcfmtdesc = &FORMATDESC[ (srcpal ? srcpalfmt.m_type : srcfmt.m_type) ][1];
const uint32_t* srcmask = &srcfmtdesc[1];
int srcbits[4];
int srcshift[4];
uint32_t srcval[4];
const int srcpixbitcount = srcfmtdesc[0];
const int srcpixsize = srcpixbitcount >> 3;
const uint8_t* srcpixbytes;
uint8_t* dstbytes = reinterpret_cast<uint8_t*>( dst );
const uint8_t* dstpalbytes = reinterpret_cast<const uint8_t*>( dstpal );
const int dstpalentries = paletteEntries();
const int dstbitcount = FORMATDESC[m_type][1];
int dstsubpix = 0;
const uint32_t* dstfmtdesc = &FORMATDESC[ (dstpal ? dstpalfmt.m_type : m_type) ][1];
const uint32_t* dstmask = &dstfmtdesc[1];
int dstbits[4];
int dstshift[4];
uint32_t dstval[4];
const int dstpixbitcount = dstfmtdesc[0];
const int dstpixsize = dstpixbitcount >> 3;
const uint8_t* dstpixbytes;
// compute aux channel variables
for ( int i = 0 ; i < 4 ; ++i )
{
srcbits[i] = countBits( srcmask[i] );
srcshift[i] = maskToShift( srcmask[i] );
dstbits[i] = countBits( dstmask[i] );
dstshift[i] = maskToShift( dstmask[i] );
}
for ( int i = 0 ; i < pixels ; ++i )
{
// apply palette if any
if ( srcpal )
{
int ix = (*srcbytes >> (srcbitoffs-srcsubpix&7)) & (srcpalentries-1);
//dbg::Debug::println( "srcbyte 0x%x results in index %i with subpix %i", (uint32_t)*srcbytes, ix, srcsubpix );
assert( (unsigned)ix < (unsigned)srcpalentries ); // color index out of source palette range
srcpixbytes = srcpalbytes + ix*srcpixsize;
}
else
{
srcpixbytes = srcbytes;
}
// read pixel data
uint32_t srcpix = *srcpixbytes;
switch ( srcpixbitcount )
{
case 32: srcpix |= (uint32_t)srcpixbytes[3] << 24; // fall-through -> 24
case 24: srcpix |= (uint32_t)srcpixbytes[2] << 16; // fall-through -> 16
case 16: srcpix |= (uint32_t)srcpixbytes[1] << 8; break;
}
// convert pixel to R8G8B8A8
for ( int k = 0 ; k < 4 ; ++k )
srcval[k] = ( (srcpix & srcmask[k]) >> srcshift[k] ) << (8-srcbits[k]);
//dbg::Debug::println( "srcval = (0x%X,0x%X,0x%X,0x%X)", srcval[0], srcval[1], srcval[2], srcval[3] );
// convert R8G8B8A8 to destination format
uint32_t dstpix = uint32_t(-1);
if ( dstpal )
{
// find best match in dst palette
int mindist = 1<<30;
dstpixbytes = dstpalbytes;
//dbg::Debug::println( "searching dst palette[%i]", dstpalentries );
for ( int n = 0 ; n < dstpalentries ; ++n )
{
// read dst palette data
uint32_t pix = *dstpixbytes;
switch ( dstpixbitcount )
{
case 32: pix |= (uint32_t)dstpixbytes[3] << 24; // fall-through -> 24
case 24: pix |= (uint32_t)dstpixbytes[2] << 16; // fall-through -> 16
case 16: pix |= (uint32_t)dstpixbytes[1] << 8; break;
}
// convert dst palette data and compute distance to target color
int dist = 0;
for ( int k = 0 ; k < 4 ; ++k )
{
dstval[k] = ( (pix & dstmask[k]) >> dstshift[k] ) << (8-dstbits[k]);
dist += (dstval[k]-srcval[k]) * (dstval[k]-srcval[k]);
}
//dbg::Debug::println( "dstval = (0x%X,0x%X,0x%X,0x%X)", dstval[0], dstval[1], dstval[2], dstval[3] );
// find closest color
if ( dist < mindist )
{
mindist = dist;
dstpix = n;
if ( 0 == mindist )
break;
}
dstpixbytes += dstpixsize;
}
}
else
{
// convert channels to destination format
for ( int k = 0 ; k < 4 ; ++k )
{
uint32_t dstv = ( srcval[k] >> (8-dstbits[k]) ) << dstshift[k];
dstpix = (dstpix & ~dstmask[k]) | dstv;
if ( 0 == srcbits[k] )
dstpix |= dstmask[k];
}
}
// write data
switch ( dstbitcount )
{
case 32: dstbytes[3] = (uint8_t)( dstpix >> 24 ); // fall-through -> 24
case 24: dstbytes[2] = (uint8_t)( dstpix >> 16 ); // fall-through -> 16
case 16: dstbytes[1] = (uint8_t)( dstpix >> 8 ); // fall-through -> 8
case 8: dstbytes[0] = (uint8_t)( dstpix ); break;
case 4: dstbytes[0] = (uint8_t)( dstbytes[0] & (~(0xF << dstsubpix)) );
dstbytes[0] = (uint8_t)( dstbytes[0] + (dstpix << dstsubpix) );
}
srcsubpix += srcbitcount;
srcbytes += srcsubpix>>3;
srcsubpix &= 7;
dstsubpix += dstbitcount;
dstbytes += dstsubpix>>3;
dstsubpix &= 7;
}
}
const char* SurfaceFormat::toString() const
{
assert( m_type < SURFACE_LAST );
return FORMAT_NAMES[m_type];
}
} // gr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -