|
|
//======= 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
|