|
|
//======= Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//=============================================================================//
#ifdef IS_WINDOWS_PC
#include <windows.h>
#endif
#include "bitmap/imageformat.h"
#include "basetypes.h"
#include "tier0/dbg.h"
#ifndef _PS3
#include <malloc.h>
#include <memory.h>
#endif
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
#include "tier1/utlmemory.h"
#include "tier1/strtools.h"
#include "mathlib/compressed_vector.h"
#include "nvtc.h"
#if defined( POSIX ) && !defined( _PS3 )
typedef int32 *DWORD_PTR; #endif
#include "bitmap/floatbitmap.h"
#define STB_DXT_IMPLEMENTATION
#include "bitmap/stb_dxt.h"
// Should be last include
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Various important function types for each color format
//-----------------------------------------------------------------------------
typedef void (*UserFormatToRGBA8888Func_t )( const uint8 *src, uint8 *dst, int numPixels ); typedef void (*RGBA8888ToUserFormatFunc_t )( const uint8 *src, uint8 *dst, int numPixels );
namespace ImageLoader {
// Color Conversion functions
static void RGBA8888ToRGBA32323232F( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToRGB323232F( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToRG3232F( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToR32F( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToABGR8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToRGB888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToBGR888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToRGB565( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToI8( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToIA88( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToP8( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToA8( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToRGB888_BLUESCREEN( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToBGR888_BLUESCREEN( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToARGB8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToBGRA8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToBGRX8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToBGR565( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToBGRX5551( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToBGRA5551( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToBGRA4444( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToUV88( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToUVWQ8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToUVLX8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA8888ToRGBA16161616F( const uint8 *src, uint8 *dst, int numPixels );
static void ABGR8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGB888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void BGR888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGB565ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void I8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void IA88ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void P8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void A8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGB888_BLUESCREENToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void BGR888_BLUESCREENToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void ARGB8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void BGRA8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void BGRX8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void BGR565ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void BGRX5551ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void BGRA5551ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void BGRA4444ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void UV88ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void UVWQ8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void UVLX8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); static void RGBA16161616ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ); //static void RGBA16161616FToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static UserFormatToRGBA8888Func_t GetUserFormatToRGBA8888Func_t( ImageFormat srcImageFormat ) { switch( srcImageFormat ) { case IMAGE_FORMAT_RGBA8888: return RGBA8888ToRGBA8888; case IMAGE_FORMAT_ABGR8888: return ABGR8888ToRGBA8888; case IMAGE_FORMAT_RGB888: return RGB888ToRGBA8888; case IMAGE_FORMAT_BGR888: return BGR888ToRGBA8888; case IMAGE_FORMAT_RGB565: return NULL; case IMAGE_FORMAT_I8: return I8ToRGBA8888; case IMAGE_FORMAT_IA88: return IA88ToRGBA8888; case IMAGE_FORMAT_A8: return A8ToRGBA8888; case IMAGE_FORMAT_RGB888_BLUESCREEN: return RGB888_BLUESCREENToRGBA8888; case IMAGE_FORMAT_BGR888_BLUESCREEN: return BGR888_BLUESCREENToRGBA8888; case IMAGE_FORMAT_ARGB8888: return ARGB8888ToRGBA8888; case IMAGE_FORMAT_BGRA8888: return BGRA8888ToRGBA8888; case IMAGE_FORMAT_BGRX8888: return BGRX8888ToRGBA8888; case IMAGE_FORMAT_BGR565: return BGR565ToRGBA8888; case IMAGE_FORMAT_BGRX5551: return BGRX5551ToRGBA8888; case IMAGE_FORMAT_BGRA5551: return BGRA5551ToRGBA8888; case IMAGE_FORMAT_BGRA4444: return BGRA4444ToRGBA8888; case IMAGE_FORMAT_UV88: return UV88ToRGBA8888; case IMAGE_FORMAT_UVWQ8888: return UVWQ8888ToRGBA8888; case IMAGE_FORMAT_UVLX8888: return UVLX8888ToRGBA8888; case IMAGE_FORMAT_RGBA16161616: return RGBA16161616ToRGBA8888; case IMAGE_FORMAT_RGBA16161616F: return NULL; case IMAGE_FORMAT_RGBA1010102: return NULL; case IMAGE_FORMAT_BGRA1010102: return NULL; case IMAGE_FORMAT_R16F: return NULL;
#if defined( _X360 )
case IMAGE_FORMAT_LINEAR_RGBA8888: return RGBA8888ToRGBA8888; case IMAGE_FORMAT_LINEAR_ABGR8888: return ABGR8888ToRGBA8888; case IMAGE_FORMAT_LINEAR_RGB888: return RGB888ToRGBA8888; case IMAGE_FORMAT_LINEAR_BGR888: return BGR888ToRGBA8888; case IMAGE_FORMAT_LINEAR_I8: return I8ToRGBA8888; case IMAGE_FORMAT_LINEAR_ARGB8888: return ARGB8888ToRGBA8888; case IMAGE_FORMAT_LINEAR_BGRA8888: return BGRA8888ToRGBA8888; case IMAGE_FORMAT_LINEAR_BGRX8888: return BGRX8888ToRGBA8888; case IMAGE_FORMAT_LINEAR_BGRX5551: return BGRX5551ToRGBA8888; case IMAGE_FORMAT_LINEAR_RGBA16161616: return RGBA16161616ToRGBA8888; case IMAGE_FORMAT_LINEAR_A8: return A8ToRGBA8888; #endif
default: return NULL; } }
static RGBA8888ToUserFormatFunc_t GetRGBA8888ToUserFormatFunc_t( ImageFormat dstImageFormat ) { switch( dstImageFormat ) { case IMAGE_FORMAT_RGBA32323232F: return RGBA8888ToRGBA32323232F; case IMAGE_FORMAT_RGB323232F: return RGBA8888ToRGB323232F; case IMAGE_FORMAT_RG3232F: return RGBA8888ToRG3232F; case IMAGE_FORMAT_R32F: return RGBA8888ToR32F; case IMAGE_FORMAT_RGBA8888: return RGBA8888ToRGBA8888; case IMAGE_FORMAT_ABGR8888: return RGBA8888ToABGR8888; case IMAGE_FORMAT_RGB888: return RGBA8888ToRGB888; case IMAGE_FORMAT_BGR888: return RGBA8888ToBGR888; case IMAGE_FORMAT_RGB565: return NULL; case IMAGE_FORMAT_I8: return RGBA8888ToI8; case IMAGE_FORMAT_IA88: return RGBA8888ToIA88; case IMAGE_FORMAT_A8: return RGBA8888ToA8; case IMAGE_FORMAT_RGB888_BLUESCREEN: return RGBA8888ToRGB888_BLUESCREEN; case IMAGE_FORMAT_BGR888_BLUESCREEN: return RGBA8888ToBGR888_BLUESCREEN; case IMAGE_FORMAT_ARGB8888: return RGBA8888ToARGB8888; case IMAGE_FORMAT_BGRA8888: return RGBA8888ToBGRA8888; case IMAGE_FORMAT_BGRX8888: return RGBA8888ToBGRX8888; case IMAGE_FORMAT_BGR565: return RGBA8888ToBGR565; case IMAGE_FORMAT_BGRX5551: return RGBA8888ToBGRX5551; case IMAGE_FORMAT_BGRA5551: return RGBA8888ToBGRA5551; case IMAGE_FORMAT_BGRA4444: return RGBA8888ToBGRA4444; case IMAGE_FORMAT_UV88: return RGBA8888ToUV88; case IMAGE_FORMAT_UVWQ8888: return RGBA8888ToUVWQ8888; case IMAGE_FORMAT_UVLX8888: return RGBA8888ToUVLX8888; case IMAGE_FORMAT_RGBA16161616F: return RGBA8888ToRGBA16161616F;
#if defined( _X360 )
case IMAGE_FORMAT_LINEAR_RGBA8888: return RGBA8888ToRGBA8888; case IMAGE_FORMAT_LINEAR_ABGR8888: return RGBA8888ToABGR8888; case IMAGE_FORMAT_LINEAR_RGB888: return RGBA8888ToRGB888; case IMAGE_FORMAT_LINEAR_BGR888: return RGBA8888ToBGR888; case IMAGE_FORMAT_LINEAR_I8: return RGBA8888ToI8; case IMAGE_FORMAT_LINEAR_ARGB8888: return RGBA8888ToARGB8888; case IMAGE_FORMAT_LINEAR_BGRA8888: return RGBA8888ToBGRA8888; case IMAGE_FORMAT_LINEAR_BGRX8888: return RGBA8888ToBGRX8888; case IMAGE_FORMAT_LINEAR_BGRX5551: return RGBA8888ToBGRX5551; case IMAGE_FORMAT_LINEAR_A8: return RGBA8888ToA8; #endif
default: return NULL; } }
#pragma pack(1)
struct DXTColBlock { uint16 col0; uint16 col1;
// no bit fields - use bytes
uint8 row[4]; };
struct DXTAlphaBlock3BitLinear { uint8 alpha0; uint8 alpha1;
uint8 stuff[6]; };
#pragma pack()
/*
static unsigned int RescaleBitNumber( unsigned int nSrcValue, unsigned int nSrcBits, unsigned int nScaleToBits ) { unsigned int nMaxSrc = ( 1 << nSrcBits ) - 1; float flValue = float( nSrcValue & nMaxSrc ) / float( nMaxSrc ); unsigned int nMaxDest = ( 1 << nScaleToBits ) - 1; return ( unsigned int ) ( flValue * nMaxDest ); } -- produces same results as bit-propagation below */
static unsigned int RescaleBitNumber( unsigned int nSrcValue, unsigned int nSrcBits, unsigned int nScaleToBits ) { unsigned int nMaxSrc = ( 1 << nSrcBits ) - 1;
if ( nScaleToBits > nSrcBits ) { return ( nSrcValue & nMaxSrc ) << ( nScaleToBits - nSrcBits ) | ( nSrcValue & nMaxSrc ) >> ( nSrcBits - ( nScaleToBits - nSrcBits ) ); } else { return ( nSrcValue & nMaxSrc ) >> ( nSrcBits - nScaleToBits ); } }
static inline void GetColorBlockColorsBGRA8888( DXTColBlock *pBlock, BGRA8888_t *col_0, BGRA8888_t *col_1, BGRA8888_t *col_2, BGRA8888_t *col_3, uint16 & wrd ) { // input data is assumed to be x86 order
// swap to target platform for proper dxt decoding
uint16 color0 = LittleShort( pBlock->col0 ); uint16 color1 = LittleShort( pBlock->col1 );
// shift to full precision
col_0->a = 0xff; col_0->r = RescaleBitNumber( ((BGR565_t*)&color0)->r, 5, 8 ); col_0->g = RescaleBitNumber( ((BGR565_t*)&color0)->g, 6, 8 ); col_0->b = RescaleBitNumber( ((BGR565_t*)&color0)->b, 5, 8 );
col_1->a = 0xff; col_1->r = RescaleBitNumber( ((BGR565_t*)&color1)->r, 5, 8 ); col_1->g = RescaleBitNumber( ((BGR565_t*)&color1)->g, 6, 8 ); col_1->b = RescaleBitNumber( ((BGR565_t*)&color1)->b, 5, 8 );
if ( color0 > color1 ) { // Four-color block: derive the other two colors.
// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
wrd = ((uint16)col_0->r * 2 + (uint16)col_1->r )/3; // no +1 for rounding
// as bits have been shifted to 888
col_2->r = (BYTE)wrd;
wrd = ((uint16)col_0->g * 2 + (uint16)col_1->g )/3; col_2->g = (BYTE)wrd;
wrd = ((uint16)col_0->b * 2 + (uint16)col_1->b )/3; col_2->b = (BYTE)wrd; col_2->a = 0xff;
wrd = ((uint16)col_0->r + (uint16)col_1->r *2 )/3; col_3->r = (BYTE)wrd;
wrd = ((uint16)col_0->g + (uint16)col_1->g *2 )/3; col_3->g = (BYTE)wrd;
wrd = ((uint16)col_0->b + (uint16)col_1->b *2 )/3; col_3->b = (BYTE)wrd; col_3->a = 0xff; } else { // Three-color block: derive the other color.
// 00 = color_0, 01 = color_1, 10 = color_2,
// 11 = transparent.
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
// explicit for each component, unlike some refrasts...????
wrd = ((uint16)col_0->r + (uint16)col_1->r )/2; col_2->r = (BYTE)wrd; wrd = ((uint16)col_0->g + (uint16)col_1->g )/2; col_2->g = (BYTE)wrd; wrd = ((uint16)col_0->b + (uint16)col_1->b )/2; col_2->b = (BYTE)wrd; col_2->a = 0xff;
col_3->r = 0x00; // random color to indicate alpha
col_3->g = 0xff; col_3->b = 0xff; col_3->a = 0x00; } }
template <class CDestPixel> static inline void DecodeColorBlock( CDestPixel *pOutputImage, DXTColBlock *pColorBlock, int width, BGRA8888_t *col_0, BGRA8888_t *col_1, BGRA8888_t *col_2, BGRA8888_t *col_3 ) { // width is width of image in pixels
uint32 bits; int r,n;
// bit masks = 00000011, 00001100, 00110000, 11000000
const uint32 masks[] = { 3 << 0, 3 << 2, 3 << 4, 3 << 6 }; const int shift[] = { 0, 2, 4, 6 };
// r steps through lines in y
for ( r=0; r < 4; r++, pOutputImage += width-4 ) // no width*4 as uint32 ptr inc will *4
{ // width * 4 bytes per pixel per line
// each j dxtc row is 4 lines of pixels
// n steps through pixels
for ( n=0; n < 4; n++ ) { bits = pColorBlock->row[r] & masks[n]; bits >>= shift[n];
switch( bits ) { case 0: *pOutputImage = *col_0; pOutputImage++; // increment to next output pixel
break; case 1: *pOutputImage = *col_1; pOutputImage++; break; case 2: *pOutputImage = *col_2; pOutputImage++; break; case 3: *pOutputImage = *col_3; pOutputImage++; break; default: Assert( 0 ); pOutputImage++; break; } } } }
template <class CDestPixel> static inline void DecodeAlpha3BitLinear( CDestPixel *pImPos, DXTAlphaBlock3BitLinear *pAlphaBlock, int width, int nChannelSelect = 3 ) { static BYTE gBits[4][4]; static uint16 gAlphas[8]; static BGRA8888_t gACol[4][4];
gAlphas[0] = pAlphaBlock->alpha0; gAlphas[1] = pAlphaBlock->alpha1;
// 8-alpha or 6-alpha block?
if( gAlphas[0] > gAlphas[1] ) { // 8-alpha block: derive the other 6 alphas.
// 000 = alpha_0, 001 = alpha_1, others are interpolated
gAlphas[2] = ( 6 * gAlphas[0] + gAlphas[1]) / 7; // bit code 010
gAlphas[3] = ( 5 * gAlphas[0] + 2 * gAlphas[1]) / 7; // Bit code 011
gAlphas[4] = ( 4 * gAlphas[0] + 3 * gAlphas[1]) / 7; // Bit code 100
gAlphas[5] = ( 3 * gAlphas[0] + 4 * gAlphas[1]) / 7; // Bit code 101
gAlphas[6] = ( 2 * gAlphas[0] + 5 * gAlphas[1]) / 7; // Bit code 110
gAlphas[7] = ( gAlphas[0] + 6 * gAlphas[1]) / 7; // Bit code 111
} else { // 6-alpha block: derive the other alphas.
// 000 = alpha_0, 001 = alpha_1, others are interpolated
gAlphas[2] = (4 * gAlphas[0] + gAlphas[1]) / 5; // Bit code 010
gAlphas[3] = (3 * gAlphas[0] + 2 * gAlphas[1]) / 5; // Bit code 011
gAlphas[4] = (2 * gAlphas[0] + 3 * gAlphas[1]) / 5; // Bit code 100
gAlphas[5] = ( gAlphas[0] + 4 * gAlphas[1]) / 5; // Bit code 101
gAlphas[6] = 0; // Bit code 110
gAlphas[7] = 255; // Bit code 111
}
// Decode 3-bit fields into array of 16 BYTES with same value
// first two rows of 4 pixels each:
// pRows = (Alpha3BitRows*) & ( pAlphaBlock->stuff[0] );
const uint32 mask = 0x00000007; // bits = 00 00 01 11
uint32 bits = *( (uint32*) & ( pAlphaBlock->stuff[0] ));
gBits[0][0] = (BYTE)( bits & mask ); bits >>= 3; gBits[0][1] = (BYTE)( bits & mask ); bits >>= 3; gBits[0][2] = (BYTE)( bits & mask ); bits >>= 3; gBits[0][3] = (BYTE)( bits & mask ); bits >>= 3; gBits[1][0] = (BYTE)( bits & mask ); bits >>= 3; gBits[1][1] = (BYTE)( bits & mask ); bits >>= 3; gBits[1][2] = (BYTE)( bits & mask ); bits >>= 3; gBits[1][3] = (BYTE)( bits & mask );
// now for last two rows:
bits = *( (uint32*) & ( pAlphaBlock->stuff[3] )); // last 3 bytes
gBits[2][0] = (BYTE)( bits & mask ); bits >>= 3; gBits[2][1] = (BYTE)( bits & mask ); bits >>= 3; gBits[2][2] = (BYTE)( bits & mask ); bits >>= 3; gBits[2][3] = (BYTE)( bits & mask ); bits >>= 3; gBits[3][0] = (BYTE)( bits & mask ); bits >>= 3; gBits[3][1] = (BYTE)( bits & mask ); bits >>= 3; gBits[3][2] = (BYTE)( bits & mask ); bits >>= 3; gBits[3][3] = (BYTE)( bits & mask );
// decode the codes into alpha values
int row, pix; for ( row = 0; row < 4; row++ ) { for ( pix=0; pix < 4; pix++ ) { gACol[row][pix].a = (BYTE) gAlphas[ gBits[row][pix] ];
Assert( gACol[row][pix].r == 0 ); Assert( gACol[row][pix].g == 0 ); Assert( gACol[row][pix].b == 0 ); } }
// Write out alpha values to the image bits
for ( row=0; row < 4; row++, pImPos += width-4 ) { for ( pix = 0; pix < 4; pix++ ) { // zero the alpha bits of image pixel
switch ( nChannelSelect ) { case 0: pImPos->r = ( *(( BGRA8888_t *) &(gACol[row][pix])) ).a; pImPos->g = 0; // Danger...stepping on the other color channels
pImPos->b = 0; pImPos->a = 0; break; case 1: pImPos->g = ( *(( BGRA8888_t *) &(gACol[row][pix])) ).a; break; case 2: pImPos->b = ( *(( BGRA8888_t *) &(gACol[row][pix])) ).a; break; default: case 3: pImPos->a = ( *(( BGRA8888_t *) &(gACol[row][pix])) ).a; break; }
pImPos++; } } }
template <class CDestPixel> static void ConvertFromDXT1( const uint8 *src, CDestPixel *dst, int width, int height ) { Assert( sizeof( BGRA8888_t ) == 4 ); Assert( sizeof( RGBA8888_t ) == 4 ); Assert( sizeof( RGB888_t ) == 3 ); Assert( sizeof( BGR888_t ) == 3 ); Assert( sizeof( BGR565_t ) == 2 ); Assert( sizeof( BGRA5551_t ) == 2 ); Assert( sizeof( BGRA4444_t ) == 2 );
int realWidth = 0; int realHeight = 0; CDestPixel *realDst = NULL;
// Deal with the case where we have a dimension smaller than 4.
if ( width < 4 || height < 4 ) { realWidth = width; realHeight = height; // round up to the nearest four
width = ( width + 3 ) & ~3; height = ( height + 3 ) & ~3; realDst = dst; dst = ( CDestPixel * )stackalloc( width * height * sizeof( CDestPixel ) ); Assert( dst ); } Assert( !( width % 4 ) ); Assert( !( height % 4 ) );
int xblocks, yblocks; xblocks = width >> 2; yblocks = height >> 2; CDestPixel *pDstScan = dst; uint32 *pSrcScan = ( uint32 * )src;
DXTColBlock *pBlock; BGRA8888_t col_0, col_1, col_2, col_3; uint16 wrdDummy;
int i, j; for ( j = 0; j < yblocks; j++ ) { // 8 bytes per block
pBlock = ( DXTColBlock * )( ( uint8 * )pSrcScan + j * xblocks * 8 ); for ( i=0; i < xblocks; i++, pBlock++ ) { GetColorBlockColorsBGRA8888( pBlock, &col_0, &col_1, &col_2, &col_3, wrdDummy );
// now decode the color block into the bitmap bits
// inline func:
pDstScan = dst + i*4 + j*4*width; DecodeColorBlock<CDestPixel>( pDstScan, pBlock, width, &col_0, &col_1, &col_2, &col_3 ); } }
// Deal with the case where we have a dimension smaller than 4.
if ( realDst ) { int x, y; for ( y = 0; y < realHeight; y++ ) { for ( x = 0; x < realWidth; x++ ) { realDst[x+(y*realWidth)] = dst[x+(y*width)]; } } } }
template <class CDestPixel> static void ConvertFromDXT5( const uint8 *src, CDestPixel *dst, int width, int height ) { int realWidth = 0; int realHeight = 0; CDestPixel *realDst = NULL;
// Deal with the case where we have a dimension smaller than 4.
if ( width < 4 || height < 4 ) { realWidth = width; realHeight = height; // round up to the nearest four
width = ( width + 3 ) & ~3; height = ( height + 3 ) & ~3; realDst = dst; dst = ( CDestPixel * )stackalloc( width * height * sizeof( CDestPixel ) ); Assert( dst ); } Assert( !( width % 4 ) ); Assert( !( height % 4 ) );
int xblocks, yblocks; xblocks = width >> 2; yblocks = height >> 2; CDestPixel *pDstScan = dst; uint32 *pSrcScan = ( uint32 * )src;
DXTColBlock *pBlock; DXTAlphaBlock3BitLinear *pAlphaBlock;
BGRA8888_t col_0, col_1, col_2, col_3; uint16 wrd;
int i,j; for ( j=0; j < yblocks; j++ ) { // 8 bytes per block
// 1 block for alpha, 1 block for color
pBlock = (DXTColBlock*) ( (uint8 *)pSrcScan + j * xblocks * 16 );
for ( i=0; i < xblocks; i++, pBlock ++ ) { // inline
// Get alpha block
pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock;
// inline func:
// Get color block & colors
pBlock++;
GetColorBlockColorsBGRA8888( pBlock, &col_0, &col_1, &col_2, &col_3, wrd );
pDstScan = dst + i*4 + j*4*width;
// Decode the color block into the bitmap bits
// inline func:
DecodeColorBlock<CDestPixel>( pDstScan, pBlock, width, &col_0, &col_1, &col_2, &col_3 );
// Overwrite the previous alpha bits with the alpha block
// info
DecodeAlpha3BitLinear( pDstScan, pAlphaBlock, width ); } }
// Deal with the case where we have a dimension smaller than 4.
if ( realDst ) { int x, y; for( y = 0; y < realHeight; y++ ) { for( x = 0; x < realWidth; x++ ) { realDst[x+(y*realWidth)] = dst[x+(y*width)]; } } } }
template <class CDestPixel> static void ConvertFromDXT5IgnoreAlpha( const uint8 *src, CDestPixel *dst, int width, int height ) { int realWidth = 0; int realHeight = 0; CDestPixel *realDst = NULL;
// Deal with the case where we have a dimension smaller than 4.
if ( width < 4 || height < 4 ) { realWidth = width; realHeight = height; // round up to the nearest four
width = ( width + 3 ) & ~3; height = ( height + 3 ) & ~3; realDst = dst; dst = ( CDestPixel * )stackalloc( width * height * sizeof( CDestPixel ) ); Assert( dst ); } Assert( !( width % 4 ) ); Assert( !( height % 4 ) );
int xblocks, yblocks; xblocks = width >> 2; yblocks = height >> 2; CDestPixel *pDstScan = dst; uint32 *pSrcScan = ( uint32 * )src;
DXTColBlock *pBlock;
BGRA8888_t col_0, col_1, col_2, col_3; uint16 wrd;
int i,j; for ( j=0; j < yblocks; j++ ) { // 8 bytes per block
// 1 block for alpha, 1 block for color
pBlock = (DXTColBlock*) ( (uint8 *)pSrcScan + j * xblocks * 16 );
for( i=0; i < xblocks; i++, pBlock ++ ) { // inline func:
// Get color block & colors
pBlock++;
GetColorBlockColorsBGRA8888( pBlock, &col_0, &col_1, &col_2, &col_3, wrd );
pDstScan = dst + i*4 + j*4*width;
// Decode the color block into the bitmap bits
// inline func:
DecodeColorBlock<CDestPixel>( pDstScan, pBlock, width, &col_0, &col_1, &col_2, &col_3 ); } }
// Deal with the case where we have a dimension smaller than 4.
if( realDst ) { int x, y; for( y = 0; y < realHeight; y++ ) { for( x = 0; x < realWidth; x++ ) { realDst[x+(y*realWidth)] = dst[x+(y*width)]; } } } }
template <class CDestPixel> static void ConvertFromATIxN( const uint8 *src, CDestPixel *dst, int width, int height, bool bATI2N ) { int realWidth = 0; int realHeight = 0; CDestPixel *realDst = NULL;
// Deal with the case where we have a dimension smaller than 4.
if ( width < 4 || height < 4 ) { realWidth = width; realHeight = height; // round up to the nearest four
width = ( width + 3 ) & ~3; height = ( height + 3 ) & ~3; realDst = dst; dst = ( CDestPixel * )stackalloc( width * height * sizeof( CDestPixel ) ); Assert( dst ); } Assert( !( width % 4 ) ); Assert( !( height % 4 ) );
int xblocks, yblocks; xblocks = width >> 2; yblocks = height >> 2;
CDestPixel *pDstScan = dst; uint32 *pSrcScan = ( uint32 * )src;
DXTAlphaBlock3BitLinear *pBlock;
int nBytesPerBlock = bATI2N ? 16 : 8;
int i,j; for ( j=0; j < yblocks; j++ ) { // 8 bytes per block
// 1 block for x, 1 block for y
pBlock = (DXTAlphaBlock3BitLinear*) ( (uint8 *)pSrcScan + j * xblocks * nBytesPerBlock );
for ( i=0; i < xblocks; i++, pBlock++ ) { pDstScan = dst + i*4 + j*4*width; DecodeAlpha3BitLinear( pDstScan, pBlock, width, 0 );
if ( bATI2N ) { pBlock++; DecodeAlpha3BitLinear( pDstScan, pBlock, width, 1 ); } } }
// Deal with the case where we have a dimension smaller than 4.
if ( realDst ) { int x, y; for( y = 0; y < realHeight; y++ ) { for( x = 0; x < realWidth; x++ ) { realDst[x+(y*realWidth)] = dst[x+(y*width)]; } } } }
static uint32 GetDXTCEncodeType( ImageFormat imageFormat ) { switch ( imageFormat ) { case IMAGE_FORMAT_DXT1: return S3TC_ENCODE_RGB_FULL; case IMAGE_FORMAT_DXT1_ONEBITALPHA: return S3TC_ENCODE_RGB_FULL | S3TC_ENCODE_RGB_ALPHA_COMPARE; case IMAGE_FORMAT_DXT3: return S3TC_ENCODE_RGB_FULL | S3TC_ENCODE_ALPHA_EXPLICIT; case IMAGE_FORMAT_DXT5: return S3TC_ENCODE_RGB_FULL | S3TC_ENCODE_ALPHA_INTERPOLATED; default: return 0; } }
// Use AMD compressor to convert RGBA input to ATI1N, ATI2N or DXT5_GA format
bool ConvertToATIxN( const uint8 *src, ImageFormat srcImageFormat, uint8 *dst, ImageFormat dstImageFormat, int width, int height, int srcStride, int dstStride, bool bDXT5GA = false ) { Assert( !"ATIxN is no longer supported." ); return false; }
bool ConvertToDXT( const uint8 *src, ImageFormat srcImageFormat, uint8 *dst, ImageFormat dstImageFormat, int width, int height, int srcStride, int dstStride ) { #if !defined( _X360 ) && !defined( POSIX )
// from rgb(a) to dxtN
if( srcStride != 0 || dstStride != 0 ) return false;
DDSURFACEDESC descIn; DDSURFACEDESC descOut; memset( &descIn, 0, sizeof(descIn) ); memset( &descOut, 0, sizeof(descOut) ); float weight[3] = {0.3086f, 0.6094f, 0.0820f}; uint32 dwEncodeType = GetDXTCEncodeType( dstImageFormat ); // Setup descIn
descIn.dwSize = sizeof(descIn); descIn.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_LPSURFACE | /*DDSD_PITCH | */ DDSD_PIXELFORMAT; descIn.dwWidth = width; descIn.dwHeight = height; descIn.lPitch = width * ImageLoader::SizeInBytes( srcImageFormat ); descIn.lpSurface = ( LPVOID *) src; descIn.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT ); switch ( srcImageFormat ) { case IMAGE_FORMAT_RGBA8888: descIn.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; descIn.ddpfPixelFormat.dwRGBBitCount = 32; descIn.ddpfPixelFormat.dwRBitMask = 0x0000ff; descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00; descIn.ddpfPixelFormat.dwBBitMask = 0xff0000; // must set this anyway or S3TC will lock up!!!
descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; break; case IMAGE_FORMAT_BGRA8888: descIn.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; descIn.ddpfPixelFormat.dwRGBBitCount = 32; descIn.ddpfPixelFormat.dwRBitMask = 0xFF0000; descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00; descIn.ddpfPixelFormat.dwBBitMask = 0x0000FF; // must set this anyway or S3TC will lock up!!!
descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; break; case IMAGE_FORMAT_BGRX8888: descIn.ddpfPixelFormat.dwFlags = DDPF_RGB; descIn.ddpfPixelFormat.dwRGBBitCount = 32; descIn.ddpfPixelFormat.dwRBitMask = 0xFF0000; descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00; descIn.ddpfPixelFormat.dwBBitMask = 0x0000FF; // must set this anyway or S3TC will lock up!!!
descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; break; case IMAGE_FORMAT_RGB888: descIn.ddpfPixelFormat.dwFlags = DDPF_RGB; descIn.ddpfPixelFormat.dwRGBBitCount = 24; descIn.ddpfPixelFormat.dwRBitMask = 0x0000ff; descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00; descIn.ddpfPixelFormat.dwBBitMask = 0xff0000; descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; break; default: return false; } // Setup descOut
descOut.dwSize = sizeof( descOut ); // Encode the texture
S3TCencode( &descIn, NULL, &descOut, dst, dwEncodeType, weight ); return true; #else
Assert( 0 ); return false; #endif
}
bool ConvertToDXTRuntime( const uint8 *src, ImageFormat srcImageFormat, uint8 *dst, ImageFormat dstImageFormat, int width, int height ) { // from rgba to dxtN using stb_dxt.h (source format must always be RGBA8888, dest format must be DXT1_RUNTIME or DXT5_RUNTIME
Assert( ( srcImageFormat == IMAGE_FORMAT_RGBA8888 || srcImageFormat == IMAGE_FORMAT_BGRA8888 ) && ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME || dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME ) );
const uint64 *sourcePixels = reinterpret_cast<const uint64 *>(src); uint32 *dest32 = reinterpret_cast<uint32 *>(dst); int width64 = width >> 1;
if ( srcImageFormat == IMAGE_FORMAT_BGRA8888 ) { for ( int y = 0; y < height; y += 4 ) { if ( width == 1 ) { uint32 pixelBlock[16];
const uint32 *sourcePixels32 = reinterpret_cast<const uint32 *>(src); pixelBlock[0] = sourcePixels32[0]; for ( int i = 1; i < 16; i++ ) { pixelBlock[i] = 0; }
// compress the pixelBlock into dest32
stb_compress_dxt_block( reinterpret_cast<uint8 *>(dest32), reinterpret_cast<uint8 *>(pixelBlock), (dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME) ? 1 : 0, STB_DXT_NORMAL ); dest32 += ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME ) ? 2 : 4; } else if ( width == 2 ) { // copy a 4x4 block of pixels from the source image into 'pixelBlock'
uint64 pixelBlock[8];
pixelBlock[0] = sourcePixels[0]; pixelBlock[2] = sourcePixels[width64]; pixelBlock[1] = pixelBlock[3] = pixelBlock[4] = pixelBlock[5] = pixelBlock[6] = pixelBlock[7] = sourcePixels[0];
// compress the pixelBlock into dest32
stb_compress_dxt_block( reinterpret_cast<uint8 *>(dest32), reinterpret_cast<uint8 *>(pixelBlock), (dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME) ? 1 : 0, STB_DXT_NORMAL ); dest32 += ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME ) ? 2 : 4; } else { for ( int x = 0; x < width64; x += 2 ) { // copy a 4x4 block of pixels from the source image into 'pixelBlock'
uint64 pixelBlock[8];
pixelBlock[0] = sourcePixels[x]; pixelBlock[1] = sourcePixels[x + 1]; pixelBlock[2] = sourcePixels[x + width64]; pixelBlock[3] = sourcePixels[x + width64 + 1]; pixelBlock[4] = sourcePixels[x + (width64 * 2)]; pixelBlock[5] = sourcePixels[x + (width64 * 2) + 1]; pixelBlock[6] = sourcePixels[x + (width64 * 3)]; pixelBlock[7] = sourcePixels[x + (width64 * 3) + 1];
// compress the pixelBlock into dest32
stb_compress_dxt_block( reinterpret_cast<uint8 *>(dest32), reinterpret_cast<uint8 *>(pixelBlock), (dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME) ? 1 : 0, STB_DXT_NORMAL ); dest32 += ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME ) ? 2 : 4; } } sourcePixels += (width64 << 2); } } else if ( srcImageFormat == IMAGE_FORMAT_RGBA8888 ) { for ( int y = 0; y < height; y += 4 ) { if ( width == 1 ) { uint32 pixelBlock[16];
const uint32 *sourcePixels32 = reinterpret_cast<const uint32 *>(src); pixelBlock[0] = ( sourcePixels32[0] & 0x00FF00FF ) || ( ( sourcePixels32[0] & 0xFF000000 ) >> 16 ) || ( ( sourcePixels32[0] & 0x0000FF00 ) << 16 ); for ( int i = 1; i < 16; i++ ) { pixelBlock[i] = 0; }
// compress the pixelBlock into dest32
stb_compress_dxt_block( reinterpret_cast<uint8 *>(dest32), reinterpret_cast<uint8 *>(pixelBlock), (dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME) ? 1 : 0, STB_DXT_NORMAL ); dest32 += ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME ) ? 2 : 4; } else if ( width == 2 ) { // copy a 4x4 block of pixels from the source image into 'pixelBlock'
uint64 pixelBlock[8];
pixelBlock[0] = ( sourcePixels[0] & 0x00FF00FF00FF00FFLL ) | ( ( sourcePixels[0] & 0xFF000000FF000000LL ) >> 16 ) | ( ( sourcePixels[0] & 0x0000FF000000FF00LL ) << 16 ); pixelBlock[2] = ( sourcePixels[width64] & 0x00FF00FF00FF00FFLL ) | ( ( sourcePixels[width64] & 0xFF000000FF000000LL ) >> 16 ) | ( ( sourcePixels[width64] & 0x0000FF000000FF00LL ) << 16 ); pixelBlock[1] = pixelBlock[3] = pixelBlock[4] = pixelBlock[5] = pixelBlock[6] = pixelBlock[7] = pixelBlock[0];
// compress the pixelBlock into dest32
stb_compress_dxt_block( reinterpret_cast<uint8 *>(dest32), reinterpret_cast<uint8 *>(pixelBlock), (dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME) ? 1 : 0, STB_DXT_NORMAL ); dest32 += ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME ) ? 2 : 4; } else { for ( int x = 0; x < width64; x += 2 ) { // copy a 4x4 block of pixels from the source image into 'pixelBlock'
uint64 pixelBlock[8];
pixelBlock[0] = ( sourcePixels[x] & 0xFF00FF00FF00FF00LL ) | ( ( sourcePixels[x] & 0x00FF000000FF0000LL ) >> 16 ) | ( ( sourcePixels[x] & 0x000000FF000000FFLL ) << 16 ); pixelBlock[1] = ( sourcePixels[x + 1] & 0xFF00FF00FF00FF00LL ) | ( ( sourcePixels[x + 1] & 0x00FF000000FF0000LL ) >> 16 ) | ( ( sourcePixels[x + 1] & 0x000000FF000000FFLL ) << 16 ); pixelBlock[2] = ( sourcePixels[x + width64] & 0xFF00FF00FF00FF00LL ) | ( ( sourcePixels[x + width64] & 0x00FF000000FF0000LL ) >> 16 ) | ( ( sourcePixels[x + width64] & 0x000000FF000000FFLL ) << 16 ); pixelBlock[3] = ( sourcePixels[x + width64 + 1] & 0xFF00FF00FF00FF00LL ) | ( ( sourcePixels[x + width64 + 1] & 0x00FF000000FF0000LL ) >> 16 ) | ( ( sourcePixels[x + width64 + 1] & 0x000000FF000000FFLL ) << 16 ); pixelBlock[4] = ( sourcePixels[x + (width64 * 2)] & 0xFF00FF00FF00FF00LL ) | ( ( sourcePixels[x + (width64 * 2)] & 0x00FF000000FF0000LL ) >> 16 ) | ( ( sourcePixels[x + (width64 * 2)] & 0x000000FF000000FFLL ) << 16 ); pixelBlock[5] = ( sourcePixels[x + (width64 * 2) + 1] & 0xFF00FF00FF00FF00LL ) | ( ( sourcePixels[x + (width64 * 2) + 1] & 0x00FF000000FF0000LL ) >> 16 ) | ( ( sourcePixels[x + (width64 * 2) + 1] & 0x000000FF000000FFLL ) << 16 ); pixelBlock[6] = ( sourcePixels[x + (width64 * 3)] & 0xFF00FF00FF00FF00LL ) | ( ( sourcePixels[x + (width64 * 3)] & 0x00FF000000FF0000LL ) >> 16 ) | ( ( sourcePixels[x + (width64 * 3)] & 0x000000FF000000FFLL ) << 16 ); pixelBlock[7] = ( sourcePixels[x + (width64 * 3) + 1] & 0xFF00FF00FF00FF00LL ) | ( ( sourcePixels[x + (width64 * 3) + 1] & 0x00FF000000FF0000LL ) >> 16 ) | ( ( sourcePixels[x + (width64 * 3) + 1] & 0x000000FF000000FFLL ) << 16 );
// compress the pixelBlock into dest32
stb_compress_dxt_block( reinterpret_cast<uint8 *>(dest32), reinterpret_cast<uint8 *>(pixelBlock), (dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME) ? 1 : 0, STB_DXT_NORMAL ); dest32 += ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME ) ? 2 : 4; } } sourcePixels += (width64 << 2); } } return true; }
// HDRFIXME: This assumes that the 16-bit integer values are 4.12 fixed-point.
void ConvertImageFormat_RGBA16161616_To_RGB323232F( unsigned short *pSrcImage, float *pDstImage, int width, int height ) { int srcSize = width * height * 4; unsigned short *pSrcEnd = pSrcImage + srcSize; unsigned short *pSrcScan = pSrcImage; float *pDstScan = pDstImage; for ( ; pSrcScan < pSrcEnd; pSrcScan += 4, pDstScan += 3 ) { pDstScan[0] = ( ( float )pSrcScan[0] ) * ( 1.0f / ( ( float )( 1 << 12 ) ) ); pDstScan[1] = ( ( float )pSrcScan[1] ) * ( 1.0f / ( ( float )( 1 << 12 ) ) ); pDstScan[2] = ( ( float )pSrcScan[2] ) * ( 1.0f / ( ( float )( 1 << 12 ) ) ); } }
// HDRFIXME: This assumes that the 16-bit integer values are 4.12 fixed-point.
void ConvertImageFormat_RGB323232F_To_RGBA16161616( float *pSrcImage, unsigned short *pDstImage, int width, int height ) { int srcSize = width * height * 3; float *pSrcEnd = pSrcImage + srcSize; float *pSrcScan = pSrcImage; unsigned short *pDstScan = pDstImage; for ( ; pSrcScan < pSrcEnd; pSrcScan += 3, pDstScan += 4 ) {
pDstScan[0] = ( unsigned short )MIN( 65535.0f, ( pSrcScan[0] * ( ( ( float )( 1 << 12 ) ) ) ) ); pDstScan[1] = ( unsigned short )MIN( 65535.0f, ( pSrcScan[1] * ( ( ( float )( 1 << 12 ) ) ) ) ); pDstScan[2] = ( unsigned short )MIN( 65535.0f, ( pSrcScan[2] * ( ( ( float )( 1 << 12 ) ) ) ) ); pDstScan[3] = 65535; } }
void ConvertImageFormat_RGBA16161616F_To_RGB323232F( float16 *pSrcImage, float *pDstImage, int width, int height ) { int srcSize = width * height * 4; float16 *pSrcEnd = pSrcImage + srcSize; float16 *pSrcScan = pSrcImage; float *pDstScan = pDstImage; for( ; pSrcScan < pSrcEnd; pSrcScan += 4, pDstScan += 3 ) { pDstScan[0] = pSrcScan[0].GetFloat(); pDstScan[1] = pSrcScan[1].GetFloat(); pDstScan[2] = pSrcScan[2].GetFloat(); } }
void ConvertImageFormat_RGBA16161616F_To_RGBA323232F( float16 *pSrcImage, float *pDstImage, int width, int height , size_t src_stride) { size_t s_stride=src_stride/2; for(int y=0; y<height; y++) { float16 const *pSrcScan=pSrcImage; float *pDstScan = pDstImage; for(int x=0; x<width; x++) { pDstScan[0] = pSrcScan[0].GetFloat(); pDstScan[1] = pSrcScan[1].GetFloat(); pDstScan[2] = pSrcScan[2].GetFloat(); pDstScan[3] = pSrcScan[3].GetFloat(); pDstScan+=4; pSrcScan+=4; } pSrcImage += s_stride; pDstImage+=4*width; } }
void ConvertImageFormat_RGB323232F_To_RGBA16161616F( float *pSrcImage, float16 *pDstImage, int width, int height ) { int srcSize = width * height * 3; float *pSrcEnd = pSrcImage + srcSize; float *pSrcScan = pSrcImage; float16 *pDstScan = pDstImage; for( ; pSrcScan < pSrcEnd; pSrcScan += 3, pDstScan += 4 ) { pDstScan[0].SetFloat( pSrcScan[0] ); pDstScan[1].SetFloat( pSrcScan[1] ); pDstScan[2].SetFloat( pSrcScan[2] ); } }
void ConvertImageFormat_RGB323232F_To_RGBA8888( float *pSrcImage, uint8 *dst, int width, int height ) { FloatBitMap_t flbm; flbm.Init( width, height );
// Set the pixels
for ( int y = 0; y < height; ++ y ) { for ( int x = 0; x < width; ++ x ) { float *pf = &pSrcImage[ 3 * ( x + width * y ) ]; PixRGBAF fpix; fpix.Red = pf[0]; fpix.Green = pf[1]; fpix.Blue = pf[2]; fpix.Alpha = 0.f; flbm.WritePixelRGBAF( x, y, 0, fpix ); } } // memcpy( flbm.RGBAData, pSrcImage, width * height * 4 );
flbm.CompressTo8Bits( 8.0 );
// Now, get the pixels
for ( int y = 0; y < height; ++ y ) { for ( int x = 0; x < width; ++ x ) { PixRGBAF fpix = flbm.PixelRGBAF( x, y, 0 ); PixRGBA8 pix8 = PixRGBAF_to_8( fpix );
uint8 *pch = &dst[ 4 * ( x + width * y ) ];
pch[0] = pix8.Red; pch[1] = pix8.Green; pch[2] = pix8.Blue; pch[3] = pix8.Alpha; } } }
void ConvertImageFormat_RGB323232F_To_BGRA8888( float *pSrcImage, uint8 *dst, int width, int height ) { FloatBitMap_t flbm; flbm.Init( width, height );
// Set the pixels
for ( int y = 0; y < height; ++ y ) { for ( int x = 0; x < width; ++ x ) { float *pf = &pSrcImage[ 3 * ( x + width * y ) ]; PixRGBAF fpix; fpix.Red = pf[0]; fpix.Green = pf[1]; fpix.Blue = pf[2]; fpix.Alpha = 0.f;
flbm.WritePixelRGBAF( x, y, 0, fpix ); } } // memcpy( flbm.RGBAData, pSrcImage, width * height * 4 );
flbm.CompressTo8Bits( 8.0 );
// Now, get the pixels
for ( int y = 0; y < height; ++ y ) { for ( int x = 0; x < width; ++ x ) { PixRGBAF fpix = flbm.PixelRGBAF( x, y, 0 ); PixRGBA8 pix8 = PixRGBAF_to_8( fpix );
uint8 *pch = &dst[ 4 * ( x + width * y ) ];
pch[0] = pix8.Blue; pch[1] = pix8.Green; pch[2] = pix8.Red; pch[3] = pix8.Alpha; } } }
// HDRFIXME: This assumes that the 16-bit integer values are 4.12 fixed-point.
void ConvertImageFormat_RGBA16161616_To_RGBA16161616F( unsigned short *pSrcImage, float *pDstImage, int width, int height ) { int srcSize = width * height * 4; unsigned short *pSrcEnd = pSrcImage + srcSize; unsigned short *pSrcScan = pSrcImage; float16 *pDstScan = ( float16 * )pDstImage; for( ; pSrcScan < pSrcEnd; pSrcScan += 4, pDstScan += 4 ) { pDstScan[0].SetFloat( pSrcScan[0] * ( 1.0f / ( float )( 1 << 16 ) ) ); pDstScan[1].SetFloat( pSrcScan[1] * ( 1.0f / ( float )( 1 << 16 ) ) ); pDstScan[2].SetFloat( pSrcScan[2] * ( 1.0f / ( float )( 1 << 16 ) ) ); pDstScan[3].SetFloat( pSrcScan[3] * ( 1.0f / ( float )( 1 << 16 ) ) ); } }
void ConvertImageFormat_RGBA16161616F_To_RGBA16161616( float16 *pSrcImage, unsigned short *pDstImage, int width, int height ) { int srcSize = width * height * 4; float16 *pSrcEnd = pSrcImage + srcSize; float16 *pSrcScan = pSrcImage; unsigned short *pDstScan = pDstImage; for( ; pSrcScan < pSrcEnd; pSrcScan += 4, pDstScan += 4 ) { int i; for( i = 0; i < 4; i++ ) { float val; val = pSrcScan[i].GetFloat(); val *= ( float )( 1 << 12 ); val = MAX( val, 0 ); val = MIN( val, 65535.0f ); pDstScan[i] = ( unsigned short )val; } } }
bool ConvertImageFormat( const uint8 *src, ImageFormat srcImageFormat, uint8 *dst, ImageFormat dstImageFormat, int width, int height, int srcStride, int dstStride ) { // HDRFIXME: WE NEED A BIGGER INTERMEDIATE FORMAT!!!!!
if ( srcImageFormat == IMAGE_FORMAT_RGBA16161616 ) { if ( dstImageFormat == IMAGE_FORMAT_RGB323232F ) { Assert( srcStride == 0 && dstStride == 0 ); ConvertImageFormat_RGBA16161616_To_RGB323232F( ( unsigned short * )src, ( float * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_RGBA16161616F ) { Assert( srcStride == 0 && dstStride == 0 ); ConvertImageFormat_RGBA16161616_To_RGBA16161616F( ( unsigned short * )src, ( float * )dst, width, height ); return true; } } else if ( srcImageFormat == IMAGE_FORMAT_RGBA16161616F ) { if ( dstImageFormat == IMAGE_FORMAT_RGB323232F ) { Assert( srcStride == 0 && dstStride == 0 ); ConvertImageFormat_RGBA16161616F_To_RGB323232F( ( float16 * )src, ( float * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_RGBA32323232F ) { Assert( dstStride == 0 ); ConvertImageFormat_RGBA16161616F_To_RGBA323232F( ( float16 * )src, ( float * )dst, width, height, srcStride ); return true; } if ( dstImageFormat == IMAGE_FORMAT_RGBA16161616 ) { Assert( srcStride == 0 && dstStride == 0 ); ConvertImageFormat_RGBA16161616F_To_RGBA16161616( ( float16 * )src, ( unsigned short * )dst, width, height ); return true; } } else if ( srcImageFormat == IMAGE_FORMAT_RGB323232F ) { if ( dstImageFormat == IMAGE_FORMAT_RGBA16161616 ) { Assert( srcStride == 0 && dstStride == 0 ); ConvertImageFormat_RGB323232F_To_RGBA16161616( ( float * )src, ( unsigned short * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_RGBA16161616F ) { Assert( srcStride == 0 && dstStride == 0 ); ConvertImageFormat_RGB323232F_To_RGBA16161616F( ( float * )src, ( float16 * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_RGBA8888 ) { Assert( srcStride == 0 ); ConvertImageFormat_RGB323232F_To_RGBA8888( ( float * )src, dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGRA8888 ) { Assert( srcStride == 0 ); ConvertImageFormat_RGB323232F_To_BGRA8888( ( float * )src, dst, width, height ); return true; } } // Fast path for just copying a compressed texture
if ( ( ( dstImageFormat == IMAGE_FORMAT_DXT1 || dstImageFormat == IMAGE_FORMAT_LINEAR_DXT1 || dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME || dstImageFormat == IMAGE_FORMAT_DXT3 || dstImageFormat == IMAGE_FORMAT_LINEAR_DXT3 || dstImageFormat == IMAGE_FORMAT_DXT5 || dstImageFormat == IMAGE_FORMAT_LINEAR_DXT5 || dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME || dstImageFormat == IMAGE_FORMAT_ATI1N || dstImageFormat == IMAGE_FORMAT_ATI2N ) && ( srcImageFormat == dstImageFormat ) ) || ( dstImageFormat == IMAGE_FORMAT_DXT5 && srcImageFormat == IMAGE_FORMAT_DXT5_RUNTIME ) || ( dstImageFormat == IMAGE_FORMAT_DXT1 && srcImageFormat == IMAGE_FORMAT_DXT1_RUNTIME ) || ( dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME && srcImageFormat == IMAGE_FORMAT_DXT5 ) || ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME && srcImageFormat == IMAGE_FORMAT_DXT1 ) ) { // Fast path for compressed textures . . stride doesn't make as much sense.
// Assert( srcStride == 0 && dstStride == 0 );
int memRequired; memRequired = GetMemRequired( width, height, 1, srcImageFormat, false ); memcpy( dst, src, memRequired ); return true; } else if ( ( srcImageFormat == IMAGE_FORMAT_RGBA8888 || srcImageFormat == IMAGE_FORMAT_RGB888 || // RGBA source
srcImageFormat == IMAGE_FORMAT_BGRA8888 || //
srcImageFormat == IMAGE_FORMAT_BGRX8888 ) && // and
( dstImageFormat == IMAGE_FORMAT_DXT1 || //
dstImageFormat == IMAGE_FORMAT_DXT3 || // DXT compressed dest
dstImageFormat == IMAGE_FORMAT_DXT5 ) ) { return ConvertToDXT( src, srcImageFormat, dst, dstImageFormat, width, height, 0, 0 ); } else if ( ( srcImageFormat == IMAGE_FORMAT_RGBA8888) && ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME || dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME ) ) { return ConvertToDXTRuntime( src, srcImageFormat, dst, dstImageFormat, width, height ); } else if ( ( srcImageFormat == IMAGE_FORMAT_ARGB8888 ) && // RGBA source and
( dstImageFormat == IMAGE_FORMAT_ATI1N || dstImageFormat == IMAGE_FORMAT_ATI2N ) ) // ATI compressed dest
{ return ConvertToATIxN( src, srcImageFormat, dst, dstImageFormat, width, height, srcStride, dstStride ); } else if ( ( dstImageFormat == IMAGE_FORMAT_RGBA8888 || dstImageFormat == IMAGE_FORMAT_BGRX8888 || dstImageFormat == IMAGE_FORMAT_BGRA8888 || dstImageFormat == IMAGE_FORMAT_BGRA4444 || dstImageFormat == IMAGE_FORMAT_BGRA5551 || dstImageFormat == IMAGE_FORMAT_BGRX5551 || dstImageFormat == IMAGE_FORMAT_BGR565 || dstImageFormat == IMAGE_FORMAT_BGR888 || dstImageFormat == IMAGE_FORMAT_RGB888 ) && ( srcImageFormat == IMAGE_FORMAT_DXT1 || srcImageFormat == IMAGE_FORMAT_DXT3 || srcImageFormat == IMAGE_FORMAT_DXT5 || srcImageFormat == IMAGE_FORMAT_ATI1N || srcImageFormat == IMAGE_FORMAT_ATI2N ) ) { // from dxtN to rgb(a)
if ( srcStride != 0 || dstStride != 0 ) { return false; } if ( srcImageFormat == IMAGE_FORMAT_DXT1 ) { if ( dstImageFormat == IMAGE_FORMAT_RGBA8888 ) { ConvertFromDXT1( src, ( RGBA8888_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGRA8888 || dstImageFormat == IMAGE_FORMAT_BGRX8888 ) { ConvertFromDXT1( src, ( BGRA8888_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_RGB888 ) { ConvertFromDXT1( src, ( RGB888_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGR888 ) { ConvertFromDXT1( src, ( BGR888_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGR565 ) { ConvertFromDXT1( src, ( BGR565_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGRA5551 || dstImageFormat == IMAGE_FORMAT_BGRX5551 ) { ConvertFromDXT1( src, ( BGRA5551_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGRA4444 ) { ConvertFromDXT1( src, ( BGRA4444_t * )dst, width, height ); return true; } } else if ( srcImageFormat == IMAGE_FORMAT_ATI2N ) { if ( dstImageFormat == IMAGE_FORMAT_BGRA8888 ) { ConvertFromATIxN( src, ( BGRA8888_t * )dst, width, height, true ); return true; } } else if ( srcImageFormat == IMAGE_FORMAT_ATI1N ) { if ( dstImageFormat == IMAGE_FORMAT_BGRA8888 ) { ConvertFromATIxN( src, ( BGRA8888_t * )dst, width, height, false ); return true; } } else if ( srcImageFormat == IMAGE_FORMAT_DXT5 ) { if ( dstImageFormat == IMAGE_FORMAT_RGBA8888 ) { ConvertFromDXT5( src, ( RGBA8888_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGRA8888 || dstImageFormat == IMAGE_FORMAT_BGRX8888 ) { ConvertFromDXT5( src, ( BGRA8888_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_RGB888 ) { ConvertFromDXT5IgnoreAlpha( src, ( RGB888_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGR888 ) { ConvertFromDXT5IgnoreAlpha( src, ( BGR888_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGR565 ) { ConvertFromDXT5IgnoreAlpha( src, ( BGR565_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGRA5551 || dstImageFormat == IMAGE_FORMAT_BGRX5551 ) { ConvertFromDXT5( src, ( BGRA5551_t * )dst, width, height ); return true; } if ( dstImageFormat == IMAGE_FORMAT_BGRA4444 ) { ConvertFromDXT5( src, ( BGRA4444_t * )dst, width, height ); return true; } } return false; } else if ( dstImageFormat == IMAGE_FORMAT_DXT1 || dstImageFormat == IMAGE_FORMAT_DXT3 || dstImageFormat == IMAGE_FORMAT_DXT5 || dstImageFormat == IMAGE_FORMAT_ATI1N || dstImageFormat == IMAGE_FORMAT_ATI2N || srcImageFormat == IMAGE_FORMAT_DXT1 || srcImageFormat == IMAGE_FORMAT_DXT3 || srcImageFormat == IMAGE_FORMAT_DXT5 || srcImageFormat == IMAGE_FORMAT_ATI1N || srcImageFormat == IMAGE_FORMAT_ATI2N ) { // DxtN to DxtN
Assert( IsPC() ); return false; } else { // uncompressed textures
int line; int srcPixelSize = SizeInBytes(srcImageFormat); int dstPixelSize = SizeInBytes(dstImageFormat); if ( srcStride == 0 ) { srcStride = srcPixelSize * width; } if ( dstStride == 0 ) { dstStride = dstPixelSize * width; } // Fast path...
if( ( srcImageFormat == dstImageFormat ) || ((srcImageFormat == IMAGE_FORMAT_BGRA8888) && (dstImageFormat == IMAGE_FORMAT_BGRX8888)) ) { // I have no idea why this isn't true on all platforms but I didn't want to mess with stuff
if ( ( IsGameConsole() || (srcImageFormat == IMAGE_FORMAT_RGBA32323232F ) || ( srcImageFormat == IMAGE_FORMAT_RGBA8888 ) || ( srcImageFormat == IMAGE_FORMAT_BGRA8888 ) ) && ( srcStride == dstStride ) && ( width*srcPixelSize == srcStride ) ) { // fastest path
memcpy( dst, src, height*srcStride ); return true; }
for ( line = 0; line < height; ++line ) { memcpy( dst, src, width*srcPixelSize ); dst += dstStride; src += srcStride; } return true; }
// fast version of BGRA to RGBA
if ( ( srcImageFormat == IMAGE_FORMAT_BGRA8888 ) && ( dstImageFormat == IMAGE_FORMAT_RGBA8888 ) && ( srcStride == dstStride ) ) { BGRA8888ToRGBA8888( src, dst, width * height ); return true; } // format conversion
uint8 *lineBufRGBA8888 = (uint8 *)stackalloc(width*4); UserFormatToRGBA8888Func_t userFormatToRGBA8888Func; RGBA8888ToUserFormatFunc_t RGBA8888ToUserFormatFunc; userFormatToRGBA8888Func = GetUserFormatToRGBA8888Func_t( srcImageFormat ); RGBA8888ToUserFormatFunc = GetRGBA8888ToUserFormatFunc_t( dstImageFormat ); if ( !userFormatToRGBA8888Func || !RGBA8888ToUserFormatFunc ) { return false; }
for ( line = 0; line < height; line++ ) { userFormatToRGBA8888Func( src + line * srcStride, lineBufRGBA8888, width ); RGBA8888ToUserFormatFunc( lineBufRGBA8888, dst + line * dstStride, width ); } return true; } }
//-----------------------------------------------------------------------------
// Color conversion routines
//-----------------------------------------------------------------------------
void ConvertIA88ImageToNormalMapRGBA8888( const uint8 *src, int width, int height, uint8 *dst, float bumpScale ) { float heightScale = ( 1.0f / 255.0f ) * bumpScale; float c, cx, cy; float maxDim = ( width > height ) ? width : height; float ooMaxDim = 1.0f / maxDim;
int s, t; for( t = 0; t < height; t++ ) { uint8 *dstPixel = &dst[t * width * 4]; for( s = 0; s < width; s++ ) { c = src[( t * width + s ) * 2]; cx = src[( t * width + ((s+1)%width) ) * 2]; cy = src[( ((t+1)%height) * width + s ) * 2];
// \Z (out of screen)
// \ // \ // \ // \----------- X
// |
// |
// |
// |
// |
// Y
Vector xVect, yVect, normal; xVect[0] = ooMaxDim; xVect[1] = 0.0f; xVect[2] = (cx - c) * heightScale;
yVect[0] = 0.0f; yVect[1] = ooMaxDim; yVect[2] = (cy - c) * heightScale;
CrossProduct( xVect, yVect, normal ); VectorNormalize( normal );
/* Repack the normalized vector into an RGB unsigned byte
vector in the normal map image. */ dstPixel[0] = ( uint8 )( 128 + 127*normal[0] ); dstPixel[1] = ( uint8 )( 128 + 127*normal[1] ); dstPixel[2] = ( uint8 )( 128 + 127*normal[2] ); dstPixel[3] = src[( ( t * width + s ) * 2 ) + 1]; dstPixel += 4; } } }
void ConvertNormalMapRGBA8888ToDUDVMapUVWQ8888( const uint8 *src, int width, int height, uint8 *dst_ ) { unsigned const char *lastPixel = src + width * height * 4; char *dst = ( char * )dst_; // NOTE: this is signed!!!!
for( ; src < lastPixel; src += 4, dst += 4 ) { dst[0] = ( char )( ( ( int )src[0] ) - 127 ); dst[1] = ( char )( ( ( int )src[1] ) - 127 ); dst[2] = ( char )( ( ( int )src[2] ) - 127 ); dst[3] = ( char )( ( ( int )src[3] ) - 127 ); } }
void ConvertNormalMapRGBA8888ToDUDVMapUVLX8888( const uint8 *src, int width, int height, uint8 *dst_ ) { unsigned const char *lastPixel = src + width * height * 4; char *dst = ( char * )dst_; // NOTE: this is signed!!!!
for( ; src < lastPixel; src += 4, dst += 4 ) { dst[0] = ( char )( ( ( int )src[0] ) - 127 ); dst[1] = ( char )( ( ( int )src[1] ) - 127 );
uint8 *pUDst = (uint8 *)dst; pUDst[2] = src[3]; pUDst[3] = 0xFF; } }
// Route to ATI compressor to convert normal map to DXT5 GA format
void ConvertNormalMapARGB8888ToDXT5GA( const unsigned char *src, unsigned char *dst, int width, int height ) { // Use ATI compressor to convert to DXT5 GA normal map format
ConvertToATIxN( src, IMAGE_FORMAT_ARGB8888, dst, IMAGE_FORMAT_DXT5, width, height, 0, 0, true ); }
void ConvertNormalMapRGBA8888ToDUDVMapUV88( const uint8 *src, int width, int height, uint8 *dst_ ) { unsigned const char *lastPixel = src + width * height * 4; char *dst = ( char * )dst_; // NOTE: this is signed!!!!
for( ; src < lastPixel; src += 4, dst += 2 ) { dst[0] = ( char )( ( ( int )src[0] ) - 127 ); dst[1] = ( char )( ( ( int )src[1] ) - 127 ); } }
void NormalizeNormalMapRGBA8888( uint8 *src, int numTexels ) { uint8 *lastPixel = src + numTexels * 4;
for( uint8 *pixel = src; pixel < lastPixel; pixel += 4 ) { Vector tmpVect; tmpVect[0] = ( ( float )pixel[0] - 128.0f ) * ( 1.0f / 127.0f ); tmpVect[1] = ( ( float )pixel[1] - 128.0f ) * ( 1.0f / 127.0f ); tmpVect[2] = ( ( float )pixel[2] - 128.0f ) * ( 1.0f / 127.0f );
VectorNormalize( tmpVect );
pixel[0] = ( uint8 )( 128 + 127 * tmpVect[0] ); pixel[1] = ( uint8 )( 128 + 127 * tmpVect[1] ); pixel[2] = ( uint8 )( 128 + 127 * tmpVect[2] ); } }
//-----------------------------------------------------------------------------
// Image rotation
//-----------------------------------------------------------------------------
bool RotateImageLeft( const uint8 *src, uint8 *dst, int widthHeight, ImageFormat imageFormat ) { #define SRC(x,y) src[((x)+(y)*widthHeight)*sizeInBytes]
#define DST(x,y) dst[((x)+(y)*widthHeight)*sizeInBytes]
if( IsCompressed( imageFormat ) ) { return false; }
int x, y;
uint8 tmp[4][16]; int halfWidthHeight = widthHeight >> 1; int sizeInBytes = SizeInBytes( imageFormat ); Assert( sizeInBytes <= 16 && sizeInBytes > 0 );
for( y = 0; y < halfWidthHeight; y++ ) { for( x = 0; x < halfWidthHeight; x++ ) { memcpy( tmp[0], &SRC( x, y ), sizeInBytes ); memcpy( tmp[1], &SRC( y, widthHeight-x-1 ), sizeInBytes ); memcpy( tmp[2], &SRC( widthHeight-x-1, widthHeight-y-1 ), sizeInBytes ); memcpy( tmp[3], &SRC( widthHeight-y-1, x ), sizeInBytes ); memcpy( &DST( x, y ), tmp[3], sizeInBytes ); memcpy( &DST( y, widthHeight-x-1 ), tmp[0], sizeInBytes ); memcpy( &DST( widthHeight-x-1, widthHeight-y-1 ), tmp[1], sizeInBytes ); memcpy( &DST( widthHeight-y-1, x ), tmp[2], sizeInBytes ); } } #undef SRC
#undef DST
return true; }
bool RotateImage180( const uint8 *src, uint8 *dst, int widthHeight, ImageFormat imageFormat ) { // OPTIMIZE: do this transformation directly.
if( RotateImageLeft( src, dst, widthHeight, imageFormat ) ) { return RotateImageLeft( dst, dst, widthHeight, imageFormat ); } return false; }
bool FlipImageVertically( void *pSrc, void *pDst, int nWidth, int nHeight, ImageFormat imageFormat, int nDstStride ) { if( IsCompressed( imageFormat ) ) return false;
int nSizeInBytes = SizeInBytes( imageFormat ); int nRowBytes = nSizeInBytes * nWidth; int nSrcStride = nRowBytes; if ( nDstStride == 0 ) { nDstStride = nRowBytes; }
uint8 *pSrcRow = (uint8*)pSrc; uint8 *pDstRow = (uint8*)pDst + ((nHeight-1) * nDstStride); if ( pSrc == pDst ) { uint8* pTemp = (uint8*)stackalloc( nRowBytes ); int nHalfHeight = nHeight >> 1; for ( int i = 0; i < nHalfHeight; i++ ) { memcpy( pTemp, pSrcRow, nRowBytes ); memcpy( pSrcRow, pDstRow, nRowBytes ); memcpy( pDstRow, pTemp, nRowBytes );
pSrcRow += nSrcStride; pDstRow -= nDstStride; } } else { for ( int i = 0; i < nHeight; i++ ) { memcpy( pDstRow, pSrcRow, nRowBytes ); pSrcRow += nSrcStride; pDstRow -= nDstStride; } }
return true; }
bool FlipImageHorizontally( void *pSrc, void *pDst, int nWidth, int nHeight, ImageFormat imageFormat, int nDstStride ) { if( IsCompressed( imageFormat ) ) return false;
uint8 tmp[16]; int nSizeInBytes = SizeInBytes( imageFormat ); int nRowBytes = nSizeInBytes * nWidth; Assert( nSizeInBytes <= 16 && nSizeInBytes > 0 ); int nSrcStride = nRowBytes; if ( nDstStride == 0 ) { nDstStride = nRowBytes; }
int x, y; uint8 *pSrcRow = (uint8*)pSrc; uint8 *pDstRow = (uint8*)pDst; if ( pSrc == pDst ) { int nHalfWidth = nWidth >> 1; for( y = 0; y < nHeight; y++ ) { uint8 *pSrcPixel = pSrcRow; uint8 *pDstPixel = pDstRow + nRowBytes - nSizeInBytes; for( x = 0; x < nHalfWidth; x++ ) { memcpy( tmp, pSrcPixel, nSizeInBytes ); memcpy( pSrcPixel, pDstPixel, nSizeInBytes ); memcpy( pDstPixel, tmp, nSizeInBytes );
pSrcPixel += nSizeInBytes; pDstPixel -= nSizeInBytes; }
pSrcRow += nSrcStride; pDstRow += nDstStride; } } else { for( y = 0; y < nHeight; y++ ) { uint8 *pSrcPixel = pSrcRow; uint8 *pDstPixel = pDstRow + nRowBytes - nSizeInBytes; for( x = 0; x < nWidth; x++ ) { memcpy( pDstPixel, pSrcPixel, nSizeInBytes ); pSrcPixel += nSizeInBytes; pDstPixel -= nSizeInBytes; }
pSrcRow += nSrcStride; pDstRow += nDstStride; } }
return true; }
//-----------------------------------------------------------------------------
// Image rotation
//-----------------------------------------------------------------------------
bool SwapAxes( uint8 *src, int widthHeight, ImageFormat imageFormat ) { #define SRC(x,y) src[((x)+(y)*widthHeight)*sizeInBytes]
if( IsCompressed( imageFormat ) ) { return false; }
int x, y;
uint8 tmp[4]; int sizeInBytes = SizeInBytes( imageFormat ); Assert( sizeInBytes <= 4 && sizeInBytes > 0 );
for( y = 0; y < widthHeight; y++ ) { for( x = 0; x < y; x++ ) { memcpy( tmp, &SRC( x, y ), sizeInBytes ); memcpy( &SRC( x, y ), &SRC( y, x ), sizeInBytes ); memcpy( &SRC( y, x ), tmp, sizeInBytes ); } } #undef SRC
return true; }
void RGBA8888ToRGBA16161616F( const uint8 *src, uint8 *dst, int numPixels ) { float flOO255 = 1.0f / 255.0f; float16 *pDest = (float16*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, pDest += 4 ) { pDest[0].SetFloat( src[0] * flOO255 ); pDest[1].SetFloat( src[1] * flOO255 ); pDest[2].SetFloat( src[2] * flOO255 ); pDest[3].SetFloat( src[3] * flOO255 ); } }
void RGBA8888ToRGBA32323232F( const uint8 *src, uint8 *dst, int numPixels ) { float flOO255 = 1.0f / 255.0f; float32 *pDest = (float32*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, pDest += 4 ) { pDest[0] = src[0] * flOO255; pDest[1] = src[1] * flOO255; pDest[2] = src[2] * flOO255; pDest[3] = src[3] * flOO255; } }
void RGBA8888ToRGB323232F( const uint8 *src, uint8 *dst, int numPixels ) { float flOO255 = 1.0f / 255.0f; float32 *pDest = (float32*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, pDest += 3 ) { pDest[0] = src[0] * flOO255; pDest[1] = src[1] * flOO255; pDest[2] = src[2] * flOO255; } }
void RGBA8888ToRG3232F( const uint8 *src, uint8 *dst, int numPixels ) { float flOO255 = 1.0f / 255.0f; float32 *pDest = (float32*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, pDest += 2 ) { pDest[0] = src[0] * flOO255; pDest[1] = src[1] * flOO255; } }
void RGBA8888ToR32F( const uint8 *src, uint8 *dst, int numPixels ) { float flOO255 = 1.0f / 255.0f; float32 *pDest = (float32*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4 ) { *pDest++ = src[0] * flOO255; } }
void RGBA8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { memcpy( dst, src, 4 * numPixels ); }
void RGBA8888ToABGR8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 4 ) { dst[0] = src[3]; dst[1] = src[2]; dst[2] = src[1]; dst[3] = src[0]; } }
void RGBA8888ToRGB888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 3 ) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; } }
void RGBA8888ToBGR888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 3 ) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; } }
void RGBA8888ToRGB565( const uint8 *src, uint8 *dst, int numPixels ) { Assert( 0 ); const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 2 ) { } }
void RGBA8888ToI8( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 1 ) { dst[0] = ( uint8 )( 0.299f * src[0] + 0.587f * src[1] + 0.114f * src[2] ); } }
void RGBA8888ToIA88( const uint8 *src, uint8 *dst, int numPixels ) { // fixme: need to find the proper rgb weighting
const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 2 ) { dst[0] = ( uint8 )( 0.299f * src[0] + 0.587f * src[1] + 0.114f * src[2] ); dst[1] = src[3]; } }
void RGBA8888ToP8( const uint8 *src, uint8 *dst, int numPixels ) { Assert( 0 ); }
void RGBA8888ToA8( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 1 ) { dst[0] = src[3]; } }
void RGBA8888ToRGB888_BLUESCREEN( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 3 ) { if( src[3] == 0 ) { dst[0] = 0; dst[1] = 0; dst[2] = 255; } else { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; } } }
void RGBA8888ToBGR888_BLUESCREEN( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 3 ) { if( src[3] == 0 ) { dst[2] = 0; dst[1] = 0; dst[0] = 255; } else { dst[2] = src[0]; dst[1] = src[1]; dst[0] = src[2]; } } }
void RGBA8888ToARGB8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 4 ) { dst[0] = src[3]; dst[1] = src[0]; dst[2] = src[1]; dst[3] = src[2]; } }
void RGBA8888ToBGRA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 4 ) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; dst[3] = src[3]; } }
void RGBA8888ToBGRX8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 4 ) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; } }
void RGBA8888ToBGR565( const uint8 *src, uint8 *dst, int numPixels ) { unsigned short* pDstShort = (unsigned short*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, pDstShort ++ ) { *pDstShort = ((src[0] >> 3) << 11) | ((src[1] >> 2) << 5) | (src[2] >> 3); } }
void RGBA8888ToBGRX5551( const uint8 *src, uint8 *dst, int numPixels ) { unsigned short* pDstShort = (unsigned short*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, pDstShort ++ ) { *pDstShort = ((src[0] >> 3) << 10) | ((src[1] >> 3) << 5) | (src[2] >> 3); } }
void RGBA8888ToBGRA5551( const uint8 *src, uint8 *dst, int numPixels ) { unsigned short* pDstShort = (unsigned short*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, pDstShort ++ ) { *pDstShort = ((src[0] >> 3) << 10) | ((src[1] >> 3) << 5) | (src[2] >> 3) | (src[3] >> 7) << 15; } }
void RGBA8888ToBGRA4444( const uint8 *src, uint8 *dst, int numPixels ) { unsigned short* pDstShort = (unsigned short*)dst; const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, pDstShort ++ ) { *pDstShort = ((src[0] >> 4) << 8) | ((src[1] >> 4) << 4) | (src[2] >> 4) | ((src[3] >> 4) << 12); } }
void RGBA8888ToUV88( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 2 ) { dst[0] = src[0]; dst[1] = src[1]; } }
void RGBA8888ToUVWQ8888( const uint8 *src, uint8 *dst, int numPixels ) { RGBA8888ToRGBA8888( src, dst, numPixels ); }
void RGBA8888ToUVLX8888( const uint8 *src, uint8 *dst, int numPixels ) { RGBA8888ToRGBA8888( src, dst, numPixels ); }
void ABGR8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 4 ) { dst[0] = src[3]; dst[1] = src[2]; dst[2] = src[1]; dst[3] = src[0]; } }
void RGB888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 3; for ( ; src < endSrc; src += 3, dst += 4 ) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = 255; } }
void BGR888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 3; for ( ; src < endSrc; src += 3, dst += 4 ) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; dst[3] = 255; } }
void RGB565ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { Assert( 0 ); const uint8 *endSrc = src + numPixels * 2; for ( ; src < endSrc; src += 2, dst += 4 ) { } }
void I8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels; for ( ; src < endSrc; src += 1, dst += 4 ) { dst[0] = src[0]; dst[1] = src[0]; dst[2] = src[0]; dst[3] = 255; } }
void IA88ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 2; for ( ; src < endSrc; src += 2, dst += 4 ) { dst[0] = src[0]; dst[1] = src[0]; dst[2] = src[0]; dst[3] = src[1]; } }
void P8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { Assert( 0 ); }
void A8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels; for ( ; src < endSrc; src += 1, dst += 4 ) { dst[0] = src[0]; dst[1] = src[0]; dst[2] = src[0]; dst[3] = src[0]; } }
void RGB888_BLUESCREENToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 3; for ( ; src < endSrc; src += 3, dst += 4 ) { if( src[0] == 0 && src[1] == 0 && src[2] == 255 ) { dst[0] = 0; dst[1] = 0; dst[2] = 0; dst[3] = 0; } else { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = 255; } } }
void BGR888_BLUESCREENToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 3; for ( ; src < endSrc; src += 3, dst += 4 ) { if( src[2] == 0 && src[1] == 0 && src[0] == 255 ) { dst[0] = 0; dst[1] = 0; dst[2] = 0; dst[3] = 0; } else { dst[2] = src[0]; dst[1] = src[1]; dst[0] = src[2]; dst[3] = 255; } } }
void ARGB8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 4 ) { dst[0] = src[1]; dst[1] = src[2]; dst[2] = src[3]; dst[3] = src[0]; } }
void BGRA8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 4 ) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; dst[3] = src[3]; } }
void BGRX8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8 *endSrc = src + numPixels * 4; for ( ; src < endSrc; src += 4, dst += 4 ) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; dst[3] = 255; } }
void BGR565ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { unsigned short* pSrcShort = (unsigned short*)src; unsigned short* pEndSrc = pSrcShort + numPixels; for ( ; pSrcShort < pEndSrc; pSrcShort++, dst += 4 ) { int blue = (*pSrcShort & 0x1F); int green = (*pSrcShort >> 5) & 0x3F; int red = (*pSrcShort >> 11) & 0x1F;
// Expand to 8 bits
dst[0] = (red << 3) | (red >> 2); dst[1] = (green << 2) | (green >> 4); dst[2] = (blue << 3) | (blue >> 2); dst[3] = 255; } }
void BGRX5551ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { unsigned short* pSrcShort = (unsigned short*)src; unsigned short* pEndSrc = pSrcShort + numPixels; for ( ; pSrcShort < pEndSrc; pSrcShort++, dst += 4 ) { int blue = (*pSrcShort & 0x1F); int green = (*pSrcShort >> 5) & 0x1F; int red = (*pSrcShort >> 10) & 0x1F;
// Expand to 8 bits
dst[0] = (red << 3) | (red >> 2); dst[1] = (green << 3) | (green >> 2); dst[2] = (blue << 3) | (blue >> 2); dst[3] = 255; } }
void BGRA5551ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { unsigned short* pSrcShort = (unsigned short*)src; unsigned short* pEndSrc = pSrcShort + numPixels; for ( ; pSrcShort < pEndSrc; pSrcShort++, dst += 4 ) { int blue = (*pSrcShort & 0x1F); int green = (*pSrcShort >> 5) & 0x1F; int red = (*pSrcShort >> 10) & 0x1F; int alpha = *pSrcShort & ( 1 << 15 );
// Expand to 8 bits
dst[0] = (red << 3) | (red >> 2); dst[1] = (green << 3) | (green >> 2); dst[2] = (blue << 3) | (blue >> 2); // garymcthack
if( alpha ) { dst[3] = 255; } else { dst[3] = 0; } } }
void BGRA4444ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { unsigned short* pSrcShort = (unsigned short*)src; unsigned short* pEndSrc = pSrcShort + numPixels; for ( ; pSrcShort < pEndSrc; pSrcShort++, dst += 4 ) { int blue = (*pSrcShort & 0xF); int green = (*pSrcShort >> 4) & 0xF; int red = (*pSrcShort >> 8) & 0xF; int alpha = (*pSrcShort >> 12) & 0xF;
// Expand to 8 bits
// FIXME: shouldn't this be (red << 4) | red?
dst[0] = (red << 4) | (red >> 4); dst[1] = (green << 4) | (green >> 4); dst[2] = (blue << 4) | (blue >> 4); dst[3] = (alpha << 4) | (alpha >> 4); } }
void UV88ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { const uint8* pEndSrc = src + numPixels * 2; for ( ; src < pEndSrc; src += 2, dst += 4 ) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = 0; dst[3] = 0; } }
void UVWQ8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { RGBA8888ToRGBA8888( src, dst, numPixels ); }
void UVLX8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels ) { RGBA8888ToRGBA8888( src, dst, numPixels ); }
// HDRFIXME: This assumes that the 16-bit integer values are 4.12 fixed-point.
void RGBA16161616ToRGBA8888( const uint8 *src_, uint8 *dst, int numPixels ) { unsigned short *src = ( unsigned short * )src_; unsigned short *pEndSrc = src + numPixels * 4; for ( ; src < pEndSrc; src += 4, dst += 4 ) { dst[0] = MIN( 255, src[0] >> 4 ); dst[1] = MIN( 255, src[1] >> 4 ); dst[2] = MIN( 255, src[2] >> 4 ); dst[3] = MIN( 255, src[3] >> 8 ); } }
} // ImageLoader namespace ends
|