You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
895 lines
23 KiB
895 lines
23 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//===========================================================================// |
|
|
|
#ifndef PIXELWRITER_H |
|
#define PIXELWRITER_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#ifdef _WIN32 |
|
#define FORCEINLINE_PIXEL FORCEINLINE |
|
#elif POSIX |
|
#define FORCEINLINE_PIXEL inline |
|
#else |
|
#error "implement me" |
|
#endif |
|
|
|
#include "bitmap/imageformat.h" |
|
#include "tier0/dbg.h" |
|
#include "mathlib/compressed_vector.h" |
|
#include "mathlib/ssemath.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
// Color writing class |
|
//----------------------------------------------------------------------------- |
|
|
|
class CPixelWriter |
|
{ |
|
public: |
|
FORCEINLINE void SetPixelMemory( ImageFormat format, void* pMemory, int stride ); |
|
FORCEINLINE void *GetPixelMemory() { return m_pBase; } |
|
|
|
// this is no longer used: |
|
#if 0 // defined( _X360 ) |
|
// set after SetPixelMemory() |
|
FORCEINLINE void ActivateByteSwapping( bool bSwap ); |
|
#endif |
|
|
|
FORCEINLINE void Seek( int x, int y ) RESTRICT; |
|
FORCEINLINE void* SkipBytes( int n ) RESTRICT; |
|
FORCEINLINE void SkipPixels( int n ); |
|
FORCEINLINE void WritePixel( int r, int g, int b, int a = 255 ); |
|
FORCEINLINE void WritePixelNoAdvance( int r, int g, int b, int a = 255 ) RESTRICT; |
|
FORCEINLINE void WritePixelSigned( int r, int g, int b, int a = 255 ); |
|
FORCEINLINE void WritePixelNoAdvanceSigned( int r, int g, int b, int a = 255 ); |
|
FORCEINLINE void ReadPixelNoAdvance( int &r, int &g, int &b, int &a ); |
|
|
|
// Floating point formats |
|
FORCEINLINE void WritePixelNoAdvanceF( float r, float g, float b, float a = 1.0f ) RESTRICT; |
|
FORCEINLINE void WritePixelF( float r, float g, float b, float a = 1.0f ); |
|
|
|
// SIMD formats |
|
FORCEINLINE void WritePixel( FLTX4 rgba ) RESTRICT; |
|
FORCEINLINE void WritePixelNoAdvance( FLTX4 rgba ); |
|
#ifdef _X360 |
|
// here are some explicit formats so we can avoid the switch: |
|
FORCEINLINE void WritePixelNoAdvance_RGBA8888( FLTX4 rgba ); |
|
FORCEINLINE void WritePixelNoAdvance_BGRA8888( FLTX4 rgba ); |
|
// as above, but with m_pBits passed in to avoid a LHS |
|
FORCEINLINE void WritePixelNoAdvance_BGRA8888( FLTX4 rgba, void *pBits ) RESTRICT; |
|
// for writing entire SIMD registers at once when they have |
|
// already been packed, and when m_pBits is vector-aligned |
|
// (which is a requirement for write-combined memory) |
|
// offset is added to m_pBits (saving you from the obligatory |
|
// LHS of a SkipBytes) |
|
FORCEINLINE void WriteFourPixelsExplicitLocation_BGRA8888( FLTX4 rgba, int offset ); |
|
#endif |
|
|
|
|
|
FORCEINLINE unsigned char GetPixelSize() RESTRICT { return m_Size; } |
|
|
|
FORCEINLINE bool IsUsingFloatFormat() RESTRICT const; |
|
FORCEINLINE unsigned char *GetCurrentPixel() { return m_pBits; } |
|
|
|
private: |
|
enum |
|
{ |
|
PIXELWRITER_USING_FLOAT_FORMAT = 0x01, |
|
PIXELWRITER_USING_16BIT_FLOAT_FORMAT = 0x02, |
|
PIXELWRITER_SWAPBYTES = 0x04, |
|
}; |
|
|
|
unsigned char* m_pBase; |
|
unsigned char* m_pBits; |
|
unsigned short m_BytesPerRow; |
|
unsigned char m_Size; |
|
unsigned char m_nFlags; |
|
signed short m_RShift; |
|
signed short m_GShift; |
|
signed short m_BShift; |
|
signed short m_AShift; |
|
unsigned int m_RMask; |
|
unsigned int m_GMask; |
|
unsigned int m_BMask; |
|
unsigned int m_AMask; |
|
|
|
#ifdef _X360 |
|
ImageFormat m_Format; |
|
public: |
|
inline const ImageFormat &GetFormat() { return m_Format; } |
|
private: |
|
#endif |
|
}; |
|
|
|
FORCEINLINE_PIXEL bool CPixelWriter::IsUsingFloatFormat() RESTRICT const |
|
{ |
|
return (m_nFlags & PIXELWRITER_USING_FLOAT_FORMAT) != 0; |
|
} |
|
|
|
FORCEINLINE_PIXEL void CPixelWriter::SetPixelMemory( ImageFormat format, void* pMemory, int stride ) |
|
{ |
|
m_pBits = (unsigned char*)pMemory; |
|
m_pBase = m_pBits; |
|
m_BytesPerRow = (unsigned short)stride; |
|
m_nFlags = 0; |
|
#ifdef _X360 |
|
m_Format = format; |
|
#endif |
|
|
|
switch ( format ) |
|
{ |
|
case IMAGE_FORMAT_R32F: // NOTE! : the low order bits are first in this naming convention. |
|
m_Size = 4; |
|
m_RShift = 0; |
|
m_GShift = 0; |
|
m_BShift = 0; |
|
m_AShift = 0; |
|
m_RMask = 0xFFFFFFFF; |
|
m_GMask = 0x0; |
|
m_BMask = 0x0; |
|
m_AMask = 0x0; |
|
m_nFlags |= PIXELWRITER_USING_FLOAT_FORMAT; |
|
break; |
|
|
|
case IMAGE_FORMAT_RGBA32323232F: |
|
m_Size = 16; |
|
m_RShift = 0; |
|
m_GShift = 32; |
|
m_BShift = 64; |
|
m_AShift = 96; |
|
m_RMask = 0xFFFFFFFF; |
|
m_GMask = 0xFFFFFFFF; |
|
m_BMask = 0xFFFFFFFF; |
|
m_AMask = 0xFFFFFFFF; |
|
m_nFlags |= PIXELWRITER_USING_FLOAT_FORMAT; |
|
break; |
|
|
|
case IMAGE_FORMAT_RGBA16161616F: |
|
m_Size = 8; |
|
m_RShift = 0; |
|
m_GShift = 16; |
|
m_BShift = 32; |
|
m_AShift = 48; |
|
m_RMask = 0xFFFF; |
|
m_GMask = 0xFFFF; |
|
m_BMask = 0xFFFF; |
|
m_AMask = 0xFFFF; |
|
m_nFlags |= PIXELWRITER_USING_FLOAT_FORMAT | PIXELWRITER_USING_16BIT_FLOAT_FORMAT; |
|
break; |
|
|
|
case IMAGE_FORMAT_RGBA8888: |
|
#if defined( _X360 ) |
|
case IMAGE_FORMAT_LINEAR_RGBA8888: |
|
#endif |
|
m_Size = 4; |
|
m_RShift = 0; |
|
m_GShift = 8; |
|
m_BShift = 16; |
|
m_AShift = 24; |
|
m_RMask = 0xFF; |
|
m_GMask = 0xFF; |
|
m_BMask = 0xFF; |
|
m_AMask = 0xFF; |
|
break; |
|
|
|
case IMAGE_FORMAT_BGRA8888: // NOTE! : the low order bits are first in this naming convention. |
|
#if defined( _X360 ) |
|
case IMAGE_FORMAT_LINEAR_BGRA8888: |
|
#endif |
|
m_Size = 4; |
|
m_RShift = 16; |
|
m_GShift = 8; |
|
m_BShift = 0; |
|
m_AShift = 24; |
|
m_RMask = 0xFF; |
|
m_GMask = 0xFF; |
|
m_BMask = 0xFF; |
|
m_AMask = 0xFF; |
|
break; |
|
|
|
case IMAGE_FORMAT_BGRX8888: |
|
#if defined( _X360 ) |
|
case IMAGE_FORMAT_LINEAR_BGRX8888: |
|
#endif |
|
m_Size = 4; |
|
m_RShift = 16; |
|
m_GShift = 8; |
|
m_BShift = 0; |
|
m_AShift = 24; |
|
m_RMask = 0xFF; |
|
m_GMask = 0xFF; |
|
m_BMask = 0xFF; |
|
m_AMask = 0x00; |
|
break; |
|
|
|
case IMAGE_FORMAT_BGRA4444: |
|
m_Size = 2; |
|
m_RShift = 4; |
|
m_GShift = 0; |
|
m_BShift = -4; |
|
m_AShift = 8; |
|
m_RMask = 0xF0; |
|
m_GMask = 0xF0; |
|
m_BMask = 0xF0; |
|
m_AMask = 0xF0; |
|
break; |
|
|
|
case IMAGE_FORMAT_BGR888: |
|
m_Size = 3; |
|
m_RShift = 16; |
|
m_GShift = 8; |
|
m_BShift = 0; |
|
m_AShift = 0; |
|
m_RMask = 0xFF; |
|
m_GMask = 0xFF; |
|
m_BMask = 0xFF; |
|
m_AMask = 0x00; |
|
break; |
|
|
|
case IMAGE_FORMAT_BGR565: |
|
m_Size = 2; |
|
m_RShift = 8; |
|
m_GShift = 3; |
|
m_BShift = -3; |
|
m_AShift = 0; |
|
m_RMask = 0xF8; |
|
m_GMask = 0xFC; |
|
m_BMask = 0xF8; |
|
m_AMask = 0x00; |
|
break; |
|
|
|
case IMAGE_FORMAT_BGRA5551: |
|
case IMAGE_FORMAT_BGRX5551: |
|
m_Size = 2; |
|
m_RShift = 7; |
|
m_GShift = 2; |
|
m_BShift = -3; |
|
m_AShift = 8; |
|
m_RMask = 0xF8; |
|
m_GMask = 0xF8; |
|
m_BMask = 0xF8; |
|
m_AMask = 0x80; |
|
break; |
|
|
|
// GR - alpha format for HDR support |
|
case IMAGE_FORMAT_A8: |
|
m_Size = 1; |
|
m_RShift = 0; |
|
m_GShift = 0; |
|
m_BShift = 0; |
|
m_AShift = 0; |
|
m_RMask = 0x00; |
|
m_GMask = 0x00; |
|
m_BMask = 0x00; |
|
m_AMask = 0xFF; |
|
break; |
|
|
|
case IMAGE_FORMAT_UVWQ8888: |
|
m_Size = 4; |
|
m_RShift = 0; |
|
m_GShift = 8; |
|
m_BShift = 16; |
|
m_AShift = 24; |
|
m_RMask = 0xFF; |
|
m_GMask = 0xFF; |
|
m_BMask = 0xFF; |
|
m_AMask = 0xFF; |
|
break; |
|
|
|
case IMAGE_FORMAT_RGBA16161616: |
|
#if defined( _X360 ) |
|
case IMAGE_FORMAT_LINEAR_RGBA16161616: |
|
#endif |
|
m_Size = 8; |
|
if ( !IsX360() ) |
|
{ |
|
m_RShift = 0; |
|
m_GShift = 16; |
|
m_BShift = 32; |
|
m_AShift = 48; |
|
} |
|
else |
|
{ |
|
m_RShift = 48; |
|
m_GShift = 32; |
|
m_BShift = 16; |
|
m_AShift = 0; |
|
} |
|
m_RMask = 0xFFFF; |
|
m_GMask = 0xFFFF; |
|
m_BMask = 0xFFFF; |
|
m_AMask = 0xFFFF; |
|
break; |
|
|
|
case IMAGE_FORMAT_I8: |
|
// whatever goes into R is considered the intensity. |
|
m_Size = 1; |
|
m_RShift = 0; |
|
m_GShift = 0; |
|
m_BShift = 0; |
|
m_AShift = 0; |
|
m_RMask = 0xFF; |
|
m_GMask = 0x00; |
|
m_BMask = 0x00; |
|
m_AMask = 0x00; |
|
break; |
|
|
|
case IMAGE_FORMAT_RGB888: |
|
m_Size = 3; |
|
m_RShift = 0; |
|
m_GShift = 8; |
|
m_BShift = 16; |
|
m_AShift = 0; |
|
m_RMask = 0xFF; |
|
m_GMask = 0xFF; |
|
m_BMask = 0xFF; |
|
m_AMask = 0x0; |
|
break; |
|
// FIXME: Add more color formats as need arises |
|
default: |
|
{ |
|
static bool format_error_printed[NUM_IMAGE_FORMATS]; |
|
if ( !format_error_printed[format] ) |
|
{ |
|
Assert( 0 ); |
|
Msg( "CPixelWriter::SetPixelMemory: Unsupported image format %i\n", format ); |
|
format_error_printed[format] = true; |
|
} |
|
m_Size = 0; // set to zero so that we don't stomp memory for formats that we don't understand. |
|
m_RShift = 0; |
|
m_GShift = 0; |
|
m_BShift = 0; |
|
m_AShift = 0; |
|
m_RMask = 0x00; |
|
m_GMask = 0x00; |
|
m_BMask = 0x00; |
|
m_AMask = 0x00; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
#if 0 // defined( _X360 ) |
|
FORCEINLINE void CPixelWriter::ActivateByteSwapping( bool bSwap ) |
|
{ |
|
// X360TBD: Who is trying to use this? |
|
// Purposely not hooked up because PixelWriter has been ported to read/write native pixels only |
|
Assert( 0 ); |
|
|
|
if ( bSwap && !(m_nFlags & PIXELWRITER_SWAPBYTES ) ) |
|
{ |
|
m_nFlags |= PIXELWRITER_SWAPBYTES; |
|
|
|
// only tested with 4 byte formats |
|
Assert( m_Size == 4 ); |
|
} |
|
else if ( !bSwap && (m_nFlags & PIXELWRITER_SWAPBYTES ) ) |
|
{ |
|
m_nFlags &= ~PIXELWRITER_SWAPBYTES; |
|
} |
|
else |
|
{ |
|
// same state |
|
return; |
|
} |
|
|
|
// swap the shifts |
|
m_RShift = 24-m_RShift; |
|
m_GShift = 24-m_GShift; |
|
m_BShift = 24-m_BShift; |
|
m_AShift = 24-m_AShift; |
|
} |
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets where we're writing to |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::Seek( int x, int y ) RESTRICT |
|
{ |
|
m_pBits = m_pBase + y * m_BytesPerRow + x * m_Size; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Skips n bytes: |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void* CPixelWriter::SkipBytes( int n ) RESTRICT |
|
{ |
|
m_pBits += n; |
|
return m_pBits; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Skips n pixels: |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::SkipPixels( int n ) |
|
{ |
|
SkipBytes( n * m_Size ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Writes a pixel without advancing the index PC ONLY |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::WritePixelNoAdvanceF( float r, float g, float b, float a ) RESTRICT |
|
{ |
|
Assert( IsUsingFloatFormat() ); |
|
|
|
// X360TBD: Not ported |
|
Assert( IsPC() ); |
|
|
|
if (PIXELWRITER_USING_16BIT_FLOAT_FORMAT & m_nFlags) |
|
{ |
|
float16 fp16[4]; |
|
fp16[0].SetFloat( r ); |
|
fp16[1].SetFloat( g ); |
|
fp16[2].SetFloat( b ); |
|
fp16[3].SetFloat( a ); |
|
// fp16 |
|
unsigned short pBuf[4] = { 0, 0, 0, 0 }; |
|
pBuf[ m_RShift >> 4 ] |= (fp16[0].GetBits() & m_RMask) << ( m_RShift & 0xF ); |
|
pBuf[ m_GShift >> 4 ] |= (fp16[1].GetBits() & m_GMask) << ( m_GShift & 0xF ); |
|
pBuf[ m_BShift >> 4 ] |= (fp16[2].GetBits() & m_BMask) << ( m_BShift & 0xF ); |
|
pBuf[ m_AShift >> 4 ] |= (fp16[3].GetBits() & m_AMask) << ( m_AShift & 0xF ); |
|
memcpy( m_pBits, pBuf, m_Size ); |
|
} |
|
else |
|
{ |
|
// fp32 |
|
int pBuf[4] = { 0, 0, 0, 0 }; |
|
pBuf[ m_RShift >> 5 ] |= (FloatBits(r) & m_RMask) << ( m_RShift & 0x1F ); |
|
pBuf[ m_GShift >> 5 ] |= (FloatBits(g) & m_GMask) << ( m_GShift & 0x1F ); |
|
pBuf[ m_BShift >> 5 ] |= (FloatBits(b) & m_BMask) << ( m_BShift & 0x1F ); |
|
pBuf[ m_AShift >> 5 ] |= (FloatBits(a) & m_AMask) << ( m_AShift & 0x1F ); |
|
memcpy( m_pBits, pBuf, m_Size ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Writes a pixel, advances the write index |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::WritePixelF( float r, float g, float b, float a ) |
|
{ |
|
WritePixelNoAdvanceF(r, g, b, a); |
|
m_pBits += m_Size; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Writes a pixel, advances the write index |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::WritePixel( int r, int g, int b, int a ) |
|
{ |
|
WritePixelNoAdvance(r,g,b,a); |
|
m_pBits += m_Size; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Writes a pixel, advances the write index |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::WritePixelSigned( int r, int g, int b, int a ) |
|
{ |
|
WritePixelNoAdvanceSigned(r,g,b,a); |
|
m_pBits += m_Size; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Writes a pixel without advancing the index |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::WritePixelNoAdvance( int r, int g, int b, int a ) RESTRICT |
|
{ |
|
Assert( !IsUsingFloatFormat() ); |
|
|
|
if ( m_Size <= 0 ) |
|
{ |
|
return; |
|
} |
|
if ( m_Size < 5 ) |
|
{ |
|
unsigned int val = (r & m_RMask) << m_RShift; |
|
val |= (g & m_GMask) << m_GShift; |
|
val |= (m_BShift > 0) ? ((b & m_BMask) << m_BShift) : ((b & m_BMask) >> -m_BShift); |
|
val |= (a & m_AMask) << m_AShift; |
|
|
|
switch( m_Size ) |
|
{ |
|
default: |
|
Assert( 0 ); |
|
return; |
|
case 1: |
|
{ |
|
m_pBits[0] = (unsigned char)((val & 0xff)); |
|
return; |
|
} |
|
case 2: |
|
{ |
|
((unsigned short *)m_pBits)[0] = (unsigned short)((val & 0xffff)); |
|
return; |
|
} |
|
case 3: |
|
{ |
|
if ( IsPC() || !IsX360() ) |
|
{ |
|
((unsigned char *)m_pBits)[0] = (unsigned char)((val & 0xffff)); |
|
m_pBits[2] = (unsigned char)((val >> 16) & 0xff); |
|
} |
|
else |
|
{ |
|
m_pBits[0] = (unsigned char)(((val >> 16) & 0xff)); |
|
m_pBits[1] = (unsigned char)(((val >> 8 ) & 0xff)); |
|
m_pBits[2] = (unsigned char)(val & 0xff); |
|
} |
|
return; |
|
} |
|
case 4: |
|
{ |
|
((unsigned int *)m_pBits)[0] = val; |
|
return; |
|
} |
|
} |
|
} |
|
else // RGBA32323232 or RGBA16161616 -- PC only. |
|
{ |
|
AssertMsg(!IsX360(), "Unsupported lightmap format used in WritePixelNoAdvance(). This is a severe performance fault.\n"); |
|
|
|
int64 val = ( ( int64 )(r & m_RMask) ) << m_RShift; |
|
val |= ( ( int64 )(g & m_GMask) ) << m_GShift; |
|
val |= (m_BShift > 0) ? ((( int64 )( b & m_BMask)) << m_BShift) : (((int64)( b & m_BMask)) >> -m_BShift); |
|
val |= ( ( int64 )(a & m_AMask) ) << m_AShift; |
|
|
|
switch( m_Size ) |
|
{ |
|
case 6: |
|
{ |
|
if ( IsPC() || !IsX360() ) |
|
{ |
|
((unsigned int *)m_pBits)[0] = val & 0xffffffff; |
|
((unsigned short *)m_pBits)[2] = (unsigned short)( ( val >> 32 ) & 0xffff ); |
|
} |
|
else |
|
{ |
|
((unsigned int *)m_pBits)[0] = (val >> 16) & 0xffffffff; |
|
((unsigned short *)m_pBits)[2] = (unsigned short)( val & 0xffff ); |
|
} |
|
return; |
|
} |
|
case 8: |
|
{ |
|
if ( IsPC() || !IsX360() ) |
|
{ |
|
((unsigned int *)m_pBits)[0] = val & 0xffffffff; |
|
((unsigned int *)m_pBits)[1] = ( val >> 32 ) & 0xffffffff; |
|
} |
|
else |
|
{ |
|
((unsigned int *)m_pBits)[0] = ( val >> 32 ) & 0xffffffff; |
|
((unsigned int *)m_pBits)[1] = val & 0xffffffff; |
|
} |
|
return; |
|
} |
|
default: |
|
Assert( 0 ); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
#ifdef _X360 |
|
// There isn't a PC port of these because of the many varied |
|
// pixel formats the PC deals with. If you write SSE versions |
|
// of all the various necessary packers, then this can be made |
|
// to work on PC. |
|
|
|
//----------------------------------------------------------------------------- |
|
// Writes a pixel, advances the write index |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::WritePixel( FLTX4 rgba ) RESTRICT |
|
{ |
|
WritePixelNoAdvance(rgba); |
|
m_pBits += m_Size; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Writes a pixel without advancing the index |
|
// rgba are four float values, each on the range 0..255 (though they may leak |
|
// fractionally over 255 due to numerical errors earlier) |
|
//----------------------------------------------------------------------------- |
|
FORCEINLINE_PIXEL void CPixelWriter::WritePixelNoAdvance( FLTX4 rgba ) RESTRICT |
|
{ |
|
Assert( !IsUsingFloatFormat() ); |
|
|
|
switch (m_Size) |
|
{ |
|
case 0: |
|
return; |
|
case 4: |
|
{ |
|
AssertMsg((reinterpret_cast<unsigned int>(m_pBits) & 0x03) == 0,"Unaligned m_pBits in WritePixelNoAdvance!"); |
|
switch ( m_Format ) |
|
{ |
|
// note: format names are low-order-byte first. |
|
case IMAGE_FORMAT_RGBA8888: |
|
case IMAGE_FORMAT_LINEAR_RGBA8888: |
|
WritePixelNoAdvance_RGBA8888(rgba); |
|
break; |
|
|
|
case IMAGE_FORMAT_BGRA8888: // NOTE! : the low order bits are first in this naming convention. |
|
case IMAGE_FORMAT_LINEAR_BGRA8888: |
|
WritePixelNoAdvance_BGRA8888(rgba); |
|
break; |
|
|
|
|
|
default: |
|
AssertMsg1(false, "Unknown four-byte pixel format %d in lightmap write.\n", m_Format); |
|
} |
|
break; |
|
} |
|
|
|
default: |
|
AssertMsg1(false, "WritePixelNoAdvance on unsupported 360 %d-byte format\n", m_Size); |
|
break; |
|
} |
|
|
|
} |
|
|
|
|
|
// here are some explicit formats so we can avoid the switch: |
|
FORCEINLINE void CPixelWriter::WritePixelNoAdvance_RGBA8888( FLTX4 rgba ) |
|
{ |
|
// it's easier to do tiered convert-saturates here |
|
// than the d3d color convertor op |
|
|
|
// first permute |
|
const static fltx4 permReverse = XMVectorPermuteControl(3,2,1,0); |
|
fltx4 N = XMVectorPermute(rgba, rgba, permReverse); |
|
|
|
N = __vctuxs(N, 0); // convert to unsigned fixed point 0 w/ saturate |
|
N = __vpkuwus(N, N); // convert to halfword saturate |
|
N = __vpkuhus(N, N); // convert to byte saturate |
|
N = __vspltw(N, 0); // splat w-word to all four |
|
|
|
__stvewx(N, m_pBits, 0); // store whatever word happens to be aligned with m_pBits to that word |
|
} |
|
|
|
FORCEINLINE void CPixelWriter::WritePixelNoAdvance_BGRA8888( FLTX4 rgba ) |
|
{ |
|
WritePixelNoAdvance_BGRA8888( rgba, m_pBits ); |
|
} |
|
|
|
FORCEINLINE void CPixelWriter::WritePixelNoAdvance_BGRA8888( FLTX4 rgba, void * RESTRICT pBits ) RESTRICT |
|
{ |
|
// this happens to be in an order such that we can use the handy builtin packing op |
|
// clamp to 0..255 (coz it might have leaked over) |
|
static const fltx4 vTwoFiftyFive = {255.0f, 255.0f, 255.0f, 255.0f}; |
|
fltx4 N = MinSIMD(vTwoFiftyFive, rgba); |
|
|
|
// the magic number such that when mul-accummulated against rbga, |
|
// gets us a representation 3.0 + (r)*2^-22 -- puts the bits at |
|
// the bottom of the float |
|
static CONST XMVECTOR PackScale = { (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22))}; // 255.0f / (FLOAT)(1 << 22) |
|
static const XMVECTOR Three = {3.0f, 3.0f, 3.0f, 3.0f}; |
|
|
|
N = __vmaddfp(N, PackScale, Three); |
|
N = __vpkd3d(N, N, VPACK_D3DCOLOR, VPACK_32, 3); // pack to X word |
|
N = __vspltw(N, 0); // splat X |
|
|
|
// this is a nasty thing to work around the April XDK bug in __stvewx |
|
{ |
|
void * RESTRICT copyOfPBits = pBits; |
|
__stvewx(N, copyOfPBits, 0); |
|
} |
|
|
|
} |
|
|
|
// for writing entire SIMD registers at once |
|
FORCEINLINE void CPixelWriter::WriteFourPixelsExplicitLocation_BGRA8888 ( FLTX4 rgba, int offset ) |
|
{ |
|
Assert( (reinterpret_cast<unsigned int>(m_pBits) & 15) == 0 ); // assert alignment |
|
XMStoreVector4A( m_pBits + offset , rgba ); |
|
} |
|
|
|
|
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Writes a signed pixel without advancing the index |
|
//----------------------------------------------------------------------------- |
|
|
|
FORCEINLINE_PIXEL void CPixelWriter::WritePixelNoAdvanceSigned( int r, int g, int b, int a ) |
|
{ |
|
Assert( !IsUsingFloatFormat() ); |
|
|
|
if ( m_Size <= 0 ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_Size < 5 ) |
|
{ |
|
int val = (r & m_RMask) << m_RShift; |
|
val |= (g & m_GMask) << m_GShift; |
|
val |= (m_BShift > 0) ? ((b & m_BMask) << m_BShift) : ((b & m_BMask) >> -m_BShift); |
|
val |= (a & m_AMask) << m_AShift; |
|
signed char *pSignedBits = (signed char *)m_pBits; |
|
|
|
if ( IsPC() || !IsX360() ) |
|
{ |
|
switch ( m_Size ) |
|
{ |
|
case 4: |
|
pSignedBits[3] = (signed char)((val >> 24) & 0xff); |
|
// fall through intentionally. |
|
case 3: |
|
pSignedBits[2] = (signed char)((val >> 16) & 0xff); |
|
// fall through intentionally. |
|
case 2: |
|
pSignedBits[1] = (signed char)((val >> 8) & 0xff); |
|
// fall through intentionally. |
|
case 1: |
|
pSignedBits[0] = (signed char)((val & 0xff)); |
|
// fall through intentionally. |
|
return; |
|
} |
|
} |
|
else |
|
{ |
|
switch ( m_Size ) |
|
{ |
|
case 4: |
|
pSignedBits[0] = (signed char)((val >> 24) & 0xff); |
|
pSignedBits[1] = (signed char)((val >> 16) & 0xff); |
|
pSignedBits[2] = (signed char)((val >> 8) & 0xff); |
|
pSignedBits[3] = (signed char)(val & 0xff); |
|
break; |
|
case 3: |
|
pSignedBits[0] = (signed char)((val >> 16) & 0xff); |
|
pSignedBits[1] = (signed char)((val >> 8) & 0xff); |
|
pSignedBits[2] = (signed char)(val & 0xff); |
|
break; |
|
case 2: |
|
pSignedBits[0] = (signed char)((val >> 8) & 0xff); |
|
pSignedBits[1] = (signed char)(val & 0xff); |
|
break; |
|
case 1: |
|
pSignedBits[0] = (signed char)(val & 0xff); |
|
break; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
int64 val = ( ( int64 )(r & m_RMask) ) << m_RShift; |
|
val |= ( ( int64 )(g & m_GMask) ) << m_GShift; |
|
val |= (m_BShift > 0) ? ((( int64 )( b & m_BMask)) << m_BShift) : (((int64)( b & m_BMask)) >> -m_BShift); |
|
val |= ( ( int64 )(a & m_AMask) ) << m_AShift; |
|
signed char *pSignedBits = ( signed char * )m_pBits; |
|
|
|
if ( IsPC() || !IsX360() ) |
|
{ |
|
switch( m_Size ) |
|
{ |
|
case 8: |
|
pSignedBits[7] = (signed char)((val >> 56) & 0xff); |
|
pSignedBits[6] = (signed char)((val >> 48) & 0xff); |
|
// fall through intentionally. |
|
case 6: |
|
pSignedBits[5] = (signed char)((val >> 40) & 0xff); |
|
pSignedBits[4] = (signed char)((val >> 32) & 0xff); |
|
// fall through intentionally. |
|
case 4: |
|
pSignedBits[3] = (signed char)((val >> 24) & 0xff); |
|
// fall through intentionally. |
|
case 3: |
|
pSignedBits[2] = (signed char)((val >> 16) & 0xff); |
|
// fall through intentionally. |
|
case 2: |
|
pSignedBits[1] = (signed char)((val >> 8) & 0xff); |
|
// fall through intentionally. |
|
case 1: |
|
pSignedBits[0] = (signed char)((val & 0xff)); |
|
break; |
|
default: |
|
Assert( 0 ); |
|
return; |
|
} |
|
} |
|
else |
|
{ |
|
switch( m_Size ) |
|
{ |
|
case 8: |
|
pSignedBits[0] = (signed char)((val >> 56) & 0xff); |
|
pSignedBits[1] = (signed char)((val >> 48) & 0xff); |
|
pSignedBits[2] = (signed char)((val >> 40) & 0xff); |
|
pSignedBits[3] = (signed char)((val >> 32) & 0xff); |
|
pSignedBits[4] = (signed char)((val >> 24) & 0xff); |
|
pSignedBits[5] = (signed char)((val >> 16) & 0xff); |
|
pSignedBits[6] = (signed char)((val >> 8) & 0xff); |
|
pSignedBits[7] = (signed char)(val & 0xff); |
|
break; |
|
case 6: |
|
pSignedBits[0] = (signed char)((val >> 40) & 0xff); |
|
pSignedBits[1] = (signed char)((val >> 32) & 0xff); |
|
pSignedBits[2] = (signed char)((val >> 24) & 0xff); |
|
pSignedBits[3] = (signed char)((val >> 16) & 0xff); |
|
pSignedBits[4] = (signed char)((val >> 8) & 0xff); |
|
pSignedBits[5] = (signed char)(val & 0xff); |
|
break; |
|
case 4: |
|
pSignedBits[0] = (signed char)((val >> 24) & 0xff); |
|
pSignedBits[1] = (signed char)((val >> 16) & 0xff); |
|
pSignedBits[2] = (signed char)((val >> 8) & 0xff); |
|
pSignedBits[3] = (signed char)(val & 0xff); |
|
break; |
|
case 3: |
|
pSignedBits[0] = (signed char)((val >> 16) & 0xff); |
|
pSignedBits[1] = (signed char)((val >> 8) & 0xff); |
|
pSignedBits[2] = (signed char)(val & 0xff); |
|
break; |
|
case 2: |
|
pSignedBits[0] = (signed char)((val >> 8) & 0xff); |
|
pSignedBits[1] = (signed char)(val & 0xff); |
|
break; |
|
case 1: |
|
pSignedBits[0] = (signed char)(val & 0xff); |
|
break; |
|
default: |
|
Assert( 0 ); |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
FORCEINLINE_PIXEL void CPixelWriter::ReadPixelNoAdvance( int &r, int &g, int &b, int &a ) |
|
{ |
|
Assert( !IsUsingFloatFormat() ); |
|
|
|
int val = m_pBits[0]; |
|
if ( m_Size > 1 ) |
|
{ |
|
if ( IsPC() || !IsX360() ) |
|
{ |
|
val |= (int)m_pBits[1] << 8; |
|
if ( m_Size > 2 ) |
|
{ |
|
val |= (int)m_pBits[2] << 16; |
|
if ( m_Size > 3 ) |
|
{ |
|
val |= (int)m_pBits[3] << 24; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
val <<= 8; |
|
val |= (int)m_pBits[1]; |
|
if ( m_Size > 2 ) |
|
{ |
|
val <<= 8; |
|
val |= (int)m_pBits[2]; |
|
if ( m_Size > 3 ) |
|
{ |
|
val <<= 8; |
|
val |= (int)m_pBits[3]; |
|
} |
|
} |
|
} |
|
} |
|
|
|
r = (val>>m_RShift) & m_RMask; |
|
g = (val>>m_GShift) & m_GMask; |
|
b = (val>>m_BShift) & m_BMask; |
|
a = (val>>m_AShift) & m_AMask; |
|
} |
|
|
|
#endif // PIXELWRITER_H;
|
|
|