Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

833 lines
27 KiB

//======= Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $Header: $
// $NoKeywords: $
//=============================================================================//
#ifndef FLOATBITMAP_H
#define FLOATBITMAP_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/utlsoacontainer.h"
#include "mathlib/mathlib.h"
#include "bitmap/imageformat.h"
class IThreadPool;
struct PixRGBAF
{
float Red;
float Green;
float Blue;
float Alpha;
};
struct PixRGBA8
{
unsigned char Red;
unsigned char Green;
unsigned char Blue;
unsigned char Alpha;
};
inline PixRGBAF PixRGBA8_to_F( PixRGBA8 const &x )
{
PixRGBAF f;
f.Red = x.Red / float( 255.0f );
f.Green = x.Green / float( 255.0f );
f.Blue = x.Blue / float( 255.0f );
f.Alpha = x.Alpha / float( 255.0f );
return f;
}
inline PixRGBA8 PixRGBAF_to_8( PixRGBAF const &f )
{
PixRGBA8 x;
x.Red = ( unsigned char )MAX( 0, MIN( 255.0,255.0*f.Red ) );
x.Green = ( unsigned char )MAX( 0, MIN( 255.0,255.0*f.Green ) );
x.Blue = ( unsigned char )MAX( 0, MIN( 255.0,255.0*f.Blue ) );
x.Alpha = ( unsigned char )MAX( 0, MIN( 255.0,255.0*f.Alpha ) );
return x;
}
#define SPFLAGS_MAXGRADIENT 1
// bit flag options for ComputeSelfShadowedBumpmapFromHeightInAlphaChannel:
#define SSBUMP_OPTION_NONDIRECTIONAL 1 // generate ambient occlusion only
#define SSBUMP_MOD2X_DETAIL_TEXTURE 2 // scale so that a flat unshadowed
// value is 0.5, and bake rgb luminance
// in.
// attributes for csoaa container
enum FBMAttribute_t
{
FBM_ATTR_RED = 0,
FBM_ATTR_GREEN = 1,
FBM_ATTR_BLUE = 2,
FBM_ATTR_ALPHA = 3,
FBM_ATTR_COUNT
};
enum FBMAttributeMask_t
{
FBM_ATTR_RED_MASK = ( 1 << FBM_ATTR_RED ),
FBM_ATTR_GREEN_MASK = ( 1 << FBM_ATTR_GREEN ),
FBM_ATTR_BLUE_MASK = ( 1 << FBM_ATTR_BLUE ),
FBM_ATTR_ALPHA_MASK = ( 1 << FBM_ATTR_ALPHA ),
FBM_ATTR_RGB_MASK = FBM_ATTR_RED_MASK | FBM_ATTR_GREEN_MASK | FBM_ATTR_BLUE_MASK,
FBM_ATTR_RGBA_MASK = FBM_ATTR_RED_MASK | FBM_ATTR_GREEN_MASK | FBM_ATTR_BLUE_MASK | FBM_ATTR_ALPHA_MASK,
};
enum DownsampleFlags_t
{
DOWNSAMPLE_CLAMPS = 0x1,
DOWNSAMPLE_CLAMPT = 0x2,
DOWNSAMPLE_CLAMPU = 0x4,
DOWNSAMPLE_ALPHATEST = 0x10,
};
struct DownsampleInfo_t
{
int m_nFlags; // see DownsampleFlags_t
float m_flAlphaThreshhold;
float m_flAlphaHiFreqThreshhold;
};
//-----------------------------------------------------------------------------
// Float bitmap
//-----------------------------------------------------------------------------
class FloatBitMap_t : public CSOAContainer
{
typedef CSOAContainer BaseClass;
public:
FloatBitMap_t();
FloatBitMap_t( int nWidth, int nHeight, int nDepth = 1, int nAttributeMask = FBM_ATTR_RGBA_MASK ); // make one and allocate space
FloatBitMap_t( const char *pFilename ); // read one from a file (tga or pfm)
FloatBitMap_t( const FloatBitMap_t *pOrig );
// Initialize, shutdown
void Init( int nWidth, int nHeight, int nDepth = 1, int nAttributeMask = FBM_ATTR_RGBA_MASK );
void Shutdown();
// Computes the attribute mask
int GetAttributeMask() const;
// Does the bitmap have data for a particular component?
bool HasAttributeData( FBMAttribute_t a ) const;
// Compute valid attribute list
int ComputeValidAttributeList( int pIndex[4] ) const;
// Methods to initialize bitmap data
bool LoadFromPFM( const char *pFilename ); // load from floating point pixmap (.pfm) file
bool LoadFromPSD( const char *pFilename ); // load from psd file
void InitializeWithRandomPixelsFromAnotherFloatBM( const FloatBitMap_t &other );
void Clear( float r, float g, float b, float alpha ); // set all pixels to speicifed values (0..1 nominal)
void LoadFromBuffer( const void *pBuffer, size_t nBufSize, ImageFormat fmt, float flGamma ); // Assumes dimensions match the bitmap size
void LoadFromFloatBitmap( const FloatBitMap_t *pOrig );
// Methods to write bitmap data to files
bool WriteTGAFile( const char *pFilename ) const;
bool WritePFM( const char *pFilename ); // save to floating point pixmap (.pfm) file
void WriteToBuffer( void *pBuffer, size_t nBufSize, ImageFormat fmt, float flGamma ) const; // Assumes dimensions match the bitmap size
// Methods to read + write constant values
const float &ConstantValue( int comp ) const;
// Methods to read + write individual pixels
float &Pixel( int x, int y, int z, int comp ) const;
float &PixelWrapped( int x, int y, int z, int comp ) const;
float &PixelClamped( int x, int y, int z, int comp ) const;
float &Alpha( int x, int y, int z ) const;
// look up a pixel value with bilinear interpolation
float InterpolatedPixel( float x, float y, int comp ) const;
float InterpolatedPixel( float x, float y, float z, int comp ) const;
PixRGBAF PixelRGBAF( int x, int y, int z ) const;
void WritePixelRGBAF(int x, int y, int z, PixRGBAF value) const;
void WritePixel(int x, int y, int z, int comp, float value);
// Method to slam a particular channel to always be the same value
void SetChannel( int comp, float flValue );
// paste, performing boundary matching. Alpha channel can be used to make
// brush shape irregular
void SmartPaste( const FloatBitMap_t &brush, int xofs, int yofs, uint32 flags );
// force to be tileable using poisson formula
void MakeTileable( void );
void ReSize( int NewXSize, int NewYSize );
// Makes the image be a sub-range of the current image
void Crop( int x, int y, int z, int nWidth, int nHeight, int nDepth );
// find the bounds of the area that has non-zero alpha.
void GetAlphaBounds( int &minx, int &miny, int &maxx, int &maxy );
// Solve the poisson equation for an image. The alpha channel of the image controls which
// pixels are "modifiable", and can be used to set boundary conditions. Alpha=0 means the pixel
// is locked. deltas are in the order [(x,y)-(x,y-1),(x,y)-(x-1,y),(x,y)-(x+1,y),(x,y)-(x,y+1)
void Poisson( FloatBitMap_t * deltas[4],
int n_iters,
uint32 flags // SPF_xxx
);
void QuarterSize( FloatBitMap_t *pBitmap ); // get a new one downsampled
void QuarterSizeBlocky( FloatBitMap_t *pBitmap ); // get a new one downsampled
void QuarterSizeWithGaussian( FloatBitMap_t *pBitmap ); // downsample 2x using a gaussian
// Downsample using nice filter (NOTE: Dest bitmap needs to have been initialized w/ final size)
void DownsampleNiceFiltered( const DownsampleInfo_t& info, FloatBitMap_t *pBitmap );
void RaiseToPower( float pow );
void ScaleGradients( void );
void Logize( void ); // pix=log(1+pix)
void UnLogize( void ); // pix=exp(pix)-1
// compress to 8 bits converts the hdr texture to an 8 bit texture, encoding a scale factor
// in the alpha channel. upon return, the original pixel can be (approximately) recovered
// by the formula rgb*alpha*overbright.
// this function performs special numerical optimization on the texture to minimize the error
// when using bilinear filtering to read the texture.
void CompressTo8Bits( float overbright );
// decompress a bitmap converted by CompressTo8Bits
void Uncompress( float overbright );
Vector AverageColor( void ); // average rgb value of all pixels
float BrightestColor( void ); // highest vector magnitude
void ScaleRGB( float scale_factor ); // for all pixels, r,g,b*=scale_factor
// given a bitmap with height stored in the alpha channel, generate vector positions and normals
void ComputeVertexPositionsAndNormals( float flHeightScale, Vector ** ppPosOut, Vector ** ppNormalOut ) const;
// generate a normal map with height stored in alpha. uses hl2 tangent basis to support baked
// self shadowing. the bump scale maps the height of a pixel relative to the edges of the
// pixel. This function may take a while - many millions of rays may be traced. applications
// using this method need to link w/ raytrace.lib
FloatBitMap_t * ComputeSelfShadowedBumpmapFromHeightInAlphaChannel(
float bump_scale, int nrays_to_trace_per_pixel = 100,
uint32 nOptionFlags = 0 // SSBUMP_OPTION_XXX
) const;
// generate a conventional normal map from a source with height stored in alpha.
FloatBitMap_t *ComputeBumpmapFromHeightInAlphaChannel( float bump_scale ) const ;
// bilateral (edge preserving) smoothing filter. edge_threshold_value defines the difference in
// values over which filtering will not occur. Each channel is filtered independently. large
// radii will run slow, since the bilateral filter is neither separable, nor is it a
// convolution that can be done via fft.
void TileableBilateralFilter( int radius_in_pixels, float edge_threshold_value );
// Sets a thread pool for all float bitmap work to be done on
static void SetThreadPool( IThreadPool* pPool );
protected:
void QuarterSize2D( FloatBitMap_t *pDest, int nStart, int nCount );
void QuarterSize3D( FloatBitMap_t *pDest, int nStart, int nCount );
void QuarterSizeBlocky2D( FloatBitMap_t *pDest, int nStart, int nCount );
void QuarterSizeBlocky3D( FloatBitMap_t *pDest, int nStart, int nCount );
template< class T > void LoadFromBufferRGBFloat( const T *pBuffer, int nPixelCount );
template< class T > void LoadFromBufferRGB( const T *pBuffer, int nPixelCount, const float *pGammaTable );
template< class T > void LoadFromBufferRGBAFloat( const T *pBuffer, int nPixelCount );
template< class T > void LoadFromBufferRGBA( const T *pBuffer, int nPixelCount, const float *pGammaTable );
template< class T > void LoadFromBufferUV( const T *pBuffer, int nPixelCount );
template< class T > void LoadFromBufferUVWQ( const T *pBuffer, int nPixelCount );
template< class T > void LoadFromBufferUVLX( const T *pBuffer, int nPixelCount );
template< class T > void WriteToBufferRGB( T *pBuffer, int nPixelCount, const uint16 *pInvGammaTable ) const;
template< class T > void WriteToBufferRGBFloat( T *pBuffer, int nPixelCount ) const;
template< class T > void WriteToBufferRGBA( T *pBuffer, int nPixelCount, const uint16 *pInvGammaTable ) const;
template< class T > void WriteToBufferRGBAFloat( T *pBuffer, int nPixelCount ) const;
template< class T > void WriteToBufferUV( T *pBuffer, int nPixelCount ) const;
template< class T > void WriteToBufferUVWQ( T *pBuffer, int nPixelCount ) const;
template< class T > void WriteToBufferUVLX( T *pBuffer, int nPixelCount ) const;
static int CoordWrap( int nC, int nLimit );
static IThreadPool *sm_pFBMThreadPool;
};
//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
inline FloatBitMap_t::FloatBitMap_t(void)
{
}
inline void FloatBitMap_t::Init( int nXSize, int nYSize, int nZSize, int nAttributeMask )
{
PurgeData();
SetAttributeType( FBM_ATTR_RED, ATTRDATATYPE_FLOAT, ( nAttributeMask & FBM_ATTR_RED_MASK ) != 0 );
SetAttributeType( FBM_ATTR_GREEN, ATTRDATATYPE_FLOAT, ( nAttributeMask & FBM_ATTR_GREEN_MASK ) != 0 );
SetAttributeType( FBM_ATTR_BLUE, ATTRDATATYPE_FLOAT, ( nAttributeMask & FBM_ATTR_BLUE_MASK ) != 0 );
SetAttributeType( FBM_ATTR_ALPHA, ATTRDATATYPE_FLOAT, ( nAttributeMask & FBM_ATTR_ALPHA_MASK ) != 0 );
AllocateData( nXSize, nYSize, nZSize );
// Default alpha to white. All others default to 0.0 by default
if ( ( nAttributeMask & FBM_ATTR_ALPHA_MASK ) == 0 )
{
FillAttr( FBM_ATTR_ALPHA, 1.0f );
}
}
//-----------------------------------------------------------------------------
// Computes the attribute mask
//-----------------------------------------------------------------------------
inline int FloatBitMap_t::GetAttributeMask() const
{
int nMask = 0;
if ( HasAllocatedMemory( FBM_ATTR_RED ) )
nMask |= FBM_ATTR_RED_MASK;
if ( HasAllocatedMemory( FBM_ATTR_GREEN ) )
nMask |= FBM_ATTR_GREEN_MASK;
if ( HasAllocatedMemory( FBM_ATTR_BLUE ) )
nMask |= FBM_ATTR_BLUE_MASK;
if ( HasAllocatedMemory( FBM_ATTR_ALPHA ) )
nMask |= FBM_ATTR_ALPHA_MASK;
return nMask;
}
//-----------------------------------------------------------------------------
// Compute valid attribute list
//-----------------------------------------------------------------------------
inline int FloatBitMap_t::ComputeValidAttributeList( int pIndex[4] ) const
{
int nCount = 0;
if ( HasAllocatedMemory( FBM_ATTR_RED ) )
pIndex[ nCount++ ] = FBM_ATTR_RED;
if ( HasAllocatedMemory( FBM_ATTR_GREEN ) )
pIndex[ nCount++ ] = FBM_ATTR_GREEN;
if ( HasAllocatedMemory( FBM_ATTR_BLUE ) )
pIndex[ nCount++ ] = FBM_ATTR_BLUE;
if ( HasAllocatedMemory( FBM_ATTR_ALPHA ) )
pIndex[ nCount++ ] = FBM_ATTR_ALPHA;
return nCount;
}
//-----------------------------------------------------------------------------
// Does the bitmap have data for a particular component?
//-----------------------------------------------------------------------------
inline bool FloatBitMap_t::HasAttributeData( FBMAttribute_t a ) const
{
return HasAllocatedMemory( a );
}
inline int FloatBitMap_t::CoordWrap( int nC, int nLimit )
{
if ( nC >= nLimit )
{
nC %= nLimit;
}
else if ( nC < 0 )
{
nC += nLimit * ( ( -nC + nLimit-1 ) / nLimit );
}
return nC;
}
inline float &FloatBitMap_t::Pixel(int x, int y, int z, int comp) const
{
Assert( (x >= 0 ) && (x < NumCols() ) );
Assert( (y >= 0) && (y < NumRows() ) );
Assert( (z >= 0) && (z < NumSlices() ) );
float *pData = ElementPointer<float>( comp, x, y, z );
return *pData;
}
inline const float &FloatBitMap_t::ConstantValue( int comp ) const
{
Assert( !HasAllocatedMemory( comp ) );
return Pixel( 0, 0, 0, comp );
}
inline float &FloatBitMap_t::PixelWrapped(int x, int y, int z, int comp) const
{
// like Pixel except wraps around to other side
x = CoordWrap( x, NumCols() );
y = CoordWrap( y, NumRows() );
z = CoordWrap( z, NumSlices() );
return Pixel( x, y, z, comp );
}
inline float &FloatBitMap_t::PixelClamped(int x, int y, int z, int comp) const
{
// like Pixel except wraps around to other side
x = clamp( x, 0, NumCols() - 1 );
y = clamp( y, 0, NumRows() - 1 );
z = clamp( z, 0, NumSlices() - 1 );
return Pixel( x, y, z, comp );
}
inline float &FloatBitMap_t::Alpha( int x, int y, int z ) const
{
Assert( ( x >= 0 ) && ( x < NumCols() ) );
Assert( ( y >= 0 ) && ( y < NumRows() ) );
Assert( ( z >= 0 ) && ( z < NumSlices() ) );
return Pixel( x, y, z, FBM_ATTR_ALPHA );
}
inline PixRGBAF FloatBitMap_t::PixelRGBAF( int x, int y, int z ) const
{
Assert( ( x >= 0 ) && ( x < NumCols() ) );
Assert( ( y >= 0 ) && ( y < NumRows() ) );
Assert( ( z >= 0 ) && ( z < NumSlices() ) );
PixRGBAF RetPix;
RetPix.Red = Pixel( x, y, z, FBM_ATTR_RED );
RetPix.Green = Pixel( x, y, z, FBM_ATTR_GREEN );
RetPix.Blue = Pixel( x, y, z, FBM_ATTR_BLUE );
RetPix.Alpha = Pixel( x, y, z, FBM_ATTR_ALPHA );
return RetPix;
}
inline void FloatBitMap_t::WritePixelRGBAF( int x, int y, int z, PixRGBAF value ) const
{
Pixel( x, y, z, FBM_ATTR_RED ) = value.Red;
Pixel( x, y, z, FBM_ATTR_GREEN ) = value.Green;
Pixel( x, y, z, FBM_ATTR_BLUE ) = value.Blue;
Pixel( x, y, z, FBM_ATTR_ALPHA ) = value.Alpha;
}
inline void FloatBitMap_t::WritePixel(int x, int y, int z, int comp, float value)
{
Pixel( x, y, z, comp ) = value;
}
//-----------------------------------------------------------------------------
// Loads an array of image data into a buffer
//-----------------------------------------------------------------------------
template< class T > void FloatBitMap_t::LoadFromBufferRGBFloat( const T *pBuffer, int nPixelCount )
{
Assert( nPixelCount == NumCols() * NumRows() * NumSlices() );
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
Pixel( x, y, z, FBM_ATTR_RED ) = pBuffer[x].r;
Pixel( x, y, z, FBM_ATTR_GREEN ) = pBuffer[x].g;
Pixel( x, y, z, FBM_ATTR_BLUE ) = pBuffer[x].b;
Pixel( x, y, z, FBM_ATTR_ALPHA ) = 1.0f;
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::LoadFromBufferRGB( const T *pBuffer, int nPixelCount, const float *pGammaTable )
{
Assert( nPixelCount == NumCols() * NumRows() * NumSlices() );
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
Pixel( x, y, z, FBM_ATTR_RED ) = pGammaTable[ pBuffer[x].RTo10Bit( ) ];
Pixel( x, y, z, FBM_ATTR_GREEN ) = pGammaTable[ pBuffer[x].GTo10Bit( ) ];
Pixel( x, y, z, FBM_ATTR_BLUE ) = pGammaTable[ pBuffer[x].BTo10Bit( ) ];
Pixel( x, y, z, FBM_ATTR_ALPHA ) = 1.0f;
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::LoadFromBufferRGBAFloat( const T *pBuffer, int nPixelCount )
{
Assert( nPixelCount == NumCols() * NumRows() * NumSlices() );
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
Pixel( x, y, z, FBM_ATTR_RED ) = pBuffer[x].r;
Pixel( x, y, z, FBM_ATTR_GREEN ) = pBuffer[x].g;
Pixel( x, y, z, FBM_ATTR_BLUE ) = pBuffer[x].b;
Pixel( x, y, z, FBM_ATTR_ALPHA ) = pBuffer[x].a;
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::LoadFromBufferRGBA( const T *pBuffer, int nPixelCount, const float *pGammaTable )
{
float flOO1023 = 1.0f / 1023.0f;
Assert( nPixelCount == NumCols() * NumRows() * NumSlices() );
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
Pixel( x, y, z, FBM_ATTR_RED ) = pGammaTable[ pBuffer[x].RTo10Bit( ) ];
Pixel( x, y, z, FBM_ATTR_GREEN ) = pGammaTable[ pBuffer[x].GTo10Bit( ) ];
Pixel( x, y, z, FBM_ATTR_BLUE ) = pGammaTable[ pBuffer[x].BTo10Bit( ) ];
Pixel( x, y, z, FBM_ATTR_ALPHA ) = pBuffer[x].ATo10Bit( ) * flOO1023;
}
pBuffer += NumCols();
}
}
}
//-----------------------------------------------------------------------------
// Loads from UV buffers
//-----------------------------------------------------------------------------
template< class T > void FloatBitMap_t::LoadFromBufferUV( const T *pBuffer, int nPixelCount )
{
float fl2O255 = 2.0f / 255.0f;
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
Pixel( x, y, z, FBM_ATTR_RED ) = ( pBuffer[x].u + 128 ) * fl2O255 - 1.0f;
Pixel( x, y, z, FBM_ATTR_GREEN ) = ( pBuffer[x].v + 128 ) * fl2O255 - 1.0f;
Pixel( x, y, z, FBM_ATTR_BLUE ) = 0.0f;
Pixel( x, y, z, FBM_ATTR_ALPHA ) = 1.0f;
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::LoadFromBufferUVWQ( const T *pBuffer, int nPixelCount )
{
float fl2O255 = 2.0f / 255.0f;
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
Pixel( x, y, z, FBM_ATTR_RED ) = ( pBuffer[x].u + 128 ) * fl2O255 - 1.0f;
Pixel( x, y, z, FBM_ATTR_GREEN ) = ( pBuffer[x].v + 128 ) * fl2O255 - 1.0f;
Pixel( x, y, z, FBM_ATTR_BLUE ) = ( pBuffer[x].w + 128 ) * fl2O255 - 1.0f;
Pixel( x, y, z, FBM_ATTR_ALPHA ) = ( pBuffer[x].q + 128 ) * fl2O255 - 1.0f;
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::LoadFromBufferUVLX( const T *pBuffer, int nPixelCount )
{
float flOO255 = 1.0f / 255.0f;
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
Pixel( x, y, z, FBM_ATTR_RED ) = ( pBuffer[x].u + 128 ) * 2.0f * flOO255 - 1.0f;
Pixel( x, y, z, FBM_ATTR_GREEN ) = ( pBuffer[x].v + 128 ) * 2.0f * flOO255 - 1.0f;
Pixel( x, y, z, FBM_ATTR_BLUE ) = pBuffer[x].l * flOO255;
Pixel( x, y, z, FBM_ATTR_ALPHA ) = 1.0f;
}
pBuffer += NumCols();
}
}
}
//-----------------------------------------------------------------------------
// Writes an array of image data into a buffer
//-----------------------------------------------------------------------------
template< class T > void FloatBitMap_t::WriteToBufferRGBFloat( T *pBuffer, int nPixelCount ) const
{
Assert( nPixelCount == NumCols() * NumRows() * NumSlices() );
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
pBuffer[x].r = Pixel( x, y, z, FBM_ATTR_RED );
pBuffer[x].g = Pixel( x, y, z, FBM_ATTR_GREEN );
pBuffer[x].b = Pixel( x, y, z, FBM_ATTR_BLUE );
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::WriteToBufferRGB( T *pBuffer, int nPixelCount, const uint16 *pInvGammaTable ) const
{
int c;
Assert( nPixelCount == NumCols() * NumRows() * NumSlices() );
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
c = ( int )( 1023.0f * Pixel( x, y, z, FBM_ATTR_RED ) + 0.5f );
pBuffer[x].RFrom10Bit( pInvGammaTable[ clamp( c, 0, 1023 ) ] );
c = ( int )( 1023.0f * Pixel( x, y, z, FBM_ATTR_GREEN ) + 0.5f );
pBuffer[x].GFrom10Bit( pInvGammaTable[ clamp( c, 0, 1023 ) ] );
c = ( int )( 1023.0f * Pixel( x, y, z, FBM_ATTR_BLUE ) + 0.5f );
pBuffer[x].BFrom10Bit( pInvGammaTable[ clamp( c, 0, 1023 ) ] );
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::WriteToBufferRGBAFloat( T *pBuffer, int nPixelCount ) const
{
Assert( nPixelCount == NumCols() * NumRows() * NumSlices() );
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
pBuffer[x].r = Pixel( x, y, z, FBM_ATTR_RED );
pBuffer[x].g = Pixel( x, y, z, FBM_ATTR_GREEN );
pBuffer[x].b = Pixel( x, y, z, FBM_ATTR_BLUE );
pBuffer[x].a = Pixel( x, y, z, FBM_ATTR_ALPHA );
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::WriteToBufferRGBA( T *pBuffer, int nPixelCount, const uint16 *pInvGammaTable ) const
{
int c;
Assert( nPixelCount == NumCols() * NumRows() * NumSlices() );
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
c = ( int )( 1023.0f * Pixel( x, y, z, FBM_ATTR_RED ) + 0.5f );
pBuffer[x].RFrom10Bit( pInvGammaTable[ clamp( c, 0, 1023 ) ] );
c = ( int )( 1023.0f * Pixel( x, y, z, FBM_ATTR_GREEN ) + 0.5f );
pBuffer[x].GFrom10Bit( pInvGammaTable[ clamp( c, 0, 1023 ) ] );
c = ( int )( 1023.0f * Pixel( x, y, z, FBM_ATTR_BLUE ) + 0.5f );
pBuffer[x].BFrom10Bit( pInvGammaTable[ clamp( c, 0, 1023 ) ] );
c = ( int )( 1023.0f * Pixel( x, y, z, FBM_ATTR_ALPHA ) + 0.5f );
pBuffer[x].AFrom10Bit( clamp( c, 0, 1023 ) );
}
pBuffer += NumCols();
}
}
}
//-----------------------------------------------------------------------------
// Writes to UV buffers
//-----------------------------------------------------------------------------
template< class T > void FloatBitMap_t::WriteToBufferUV( T *pBuffer, int nPixelCount ) const
{
int c;
float fl255O2 = 255.0f / 2.0f;
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
c = ( int )( fl255O2 * ( Pixel( x, y, z, FBM_ATTR_RED ) + 1.0f ) );
pBuffer[x].u = clamp( c, 0, 255 ) - 128;
c = ( int )( fl255O2 * ( Pixel( x, y, z, FBM_ATTR_GREEN ) + 1.0f ) );
pBuffer[x].v = clamp( c, 0, 255 ) - 128;
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::WriteToBufferUVWQ( T *pBuffer, int nPixelCount ) const
{
int c;
float fl255O2 = 255.0f / 2.0f;
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
c = ( int )( fl255O2 * ( Pixel( x, y, z, FBM_ATTR_RED ) + 1.0f ) );
pBuffer[x].u = clamp( c, 0, 255 ) - 128;
c = ( int )( fl255O2 * ( Pixel( x, y, z, FBM_ATTR_GREEN ) + 1.0f ) );
pBuffer[x].v = clamp( c, 0, 255 ) - 128;
c = ( int )( fl255O2 * ( Pixel( x, y, z, FBM_ATTR_BLUE ) + 1.0f ) );
pBuffer[x].w = clamp( c, 0, 255 ) - 128;
c = ( int )( fl255O2 * ( Pixel( x, y, z, FBM_ATTR_ALPHA ) + 1.0f ) );
pBuffer[x].q = clamp( c, 0, 255 ) - 128;
}
pBuffer += NumCols();
}
}
}
template< class T > void FloatBitMap_t::WriteToBufferUVLX( T *pBuffer, int nPixelCount ) const
{
int c;
float fl255O2 = 255.0f / 2.0f;
for( int z = 0; z < NumSlices(); ++z )
{
for( int y = 0; y < NumRows(); ++y )
{
for( int x = 0; x < NumCols(); ++x )
{
c = ( int )( fl255O2 * ( Pixel( x, y, z, FBM_ATTR_RED ) + 1.0f ) );
pBuffer[x].u = clamp( c, 0, 255 ) - 128;
c = ( int )( fl255O2 * ( Pixel( x, y, z, FBM_ATTR_GREEN ) + 1.0f ) );
pBuffer[x].v = clamp( c, 0, 255 ) - 128;
c = ( int )( 255.0f * Pixel( x, y, z, FBM_ATTR_BLUE ) );
pBuffer[x].l = clamp( c, 0, 255 );
pBuffer[x].x = 255;
}
pBuffer += NumCols();
}
}
}
// a FloatCubeMap_t holds the floating point bitmaps for 6 faces of a cube map
class FloatCubeMap_t
{
public:
FloatBitMap_t face_maps[6];
FloatCubeMap_t(int xfsize, int yfsize)
{
// make an empty one with face dimensions xfsize x yfsize
for(int f=0;f<6;f++)
{
face_maps[f].Init(xfsize,yfsize);
}
}
// load basenamebk,pfm, basenamedn.pfm, basenameft.pfm, ...
FloatCubeMap_t(const char *basename);
// save basenamebk,pfm, basenamedn.pfm, basenameft.pfm, ...
void WritePFMs(const char *basename);
Vector AverageColor(void)
{
Vector ret(0,0,0);
int nfaces = 0;
for( int f = 0;f < 6;f ++ )
if ( face_maps[f].NumElements() )
{
nfaces++;
ret += face_maps[f].AverageColor();
}
if ( nfaces )
ret *= ( 1.0 / nfaces );
return ret;
}
float BrightestColor( void )
{
float ret = 0.0;
for( int f = 0;f < 6;f ++ )
if ( face_maps[f].NumElements() )
{
ret = MAX( ret, face_maps[f].BrightestColor() );
}
return ret;
}
// generate the N-order spherical harmonic coeffcients to approxiamte this cubemap.
// for order N, this will fill in 1 + 2 * N + N^2 vectors ( 0 = 0, 1 = 4, 2 = 9 .. )
// vectors are used to hold the r,g,b coeffs
void CalculateSphericalHarmonicApproximation( int nOrder, Vector *flCoeffs );
// inverse of above
void GenerateFromSphericalHarmonics( int nOrder, Vector const *flCoeffs );
// resample a cubemap to one of possibly a lower resolution, using a given phong exponent.
// dot-product weighting will be used for the filtering operation.
void Resample(FloatCubeMap_t &dest, float flPhongExponent);
// returns the normalized direciton vector through a given pixel of a given face
Vector PixelDirection(int face, int x, int y);
// returns the direction vector throught the center of a cubemap face
Vector FaceNormal( int nFaceNumber );
};
// Image Pyramid class.
#define MAX_IMAGE_PYRAMID_LEVELS 16 // up to 64kx64k
enum ImagePyramidMode_t
{
PYRAMID_MODE_GAUSSIAN,
};
class FloatImagePyramid_t
{
public:
int m_nLevels;
FloatBitMap_t *m_pLevels[MAX_IMAGE_PYRAMID_LEVELS]; // level 0 is highest res
FloatImagePyramid_t(void)
{
m_nLevels = 0;
memset( m_pLevels, 0, sizeof( m_pLevels ));
}
// build one. clones data from src for level 0.
FloatImagePyramid_t(const FloatBitMap_t &src, ImagePyramidMode_t mode);
// read or write a Pixel from a given level. All coordinates are specified in the same domain as the base level.
float &Pixel(int x, int y, int component, int level) const;
FloatBitMap_t *Level(int lvl) const
{
Assert( lvl < m_nLevels );
return m_pLevels[lvl];
}
// rebuild all levels above the specified level
void ReconstructLowerResolutionLevels(int starting_level);
~FloatImagePyramid_t(void);
void WriteTGAs(const char *basename) const; // outputs name_00.tga, name_01.tga,...
};
#endif