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.

1618 lines
46 KiB

  1. //===== Copyright � 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <tier0/platform.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <math.h>
  10. #include <stdlib.h>
  11. #include "bitmap/floatbitmap.h"
  12. #include <tier2/tier2.h>
  13. #include "bitmap/imageformat.h"
  14. #include "bitmap/tgaloader.h"
  15. #include "tier1/strtools.h"
  16. #include "filesystem.h"
  17. #include "vstdlib/jobthread.h"
  18. // for PSD loading
  19. #include "bitmap/bitmap.h"
  20. #include "bitmap/psd.h"
  21. #include "tier2/utlstreambuffer.h"
  22. // NOTE: This has to be the last file included!
  23. #include "tier0/memdbgon.h"
  24. //-----------------------------------------------------------------------------
  25. // Globals
  26. //-----------------------------------------------------------------------------
  27. IThreadPool *FloatBitMap_t::sm_pFBMThreadPool = NULL;
  28. //-----------------------------------------------------------------------------
  29. // Sets a thread pool for all float bitmap work to be done on
  30. //-----------------------------------------------------------------------------
  31. void FloatBitMap_t::SetThreadPool( IThreadPool* pPool )
  32. {
  33. sm_pFBMThreadPool = pPool;
  34. }
  35. //-----------------------------------------------------------------------------
  36. // Utility methods
  37. //-----------------------------------------------------------------------------
  38. #define SQ(x) ((x)*(x))
  39. // linear interpolate between 2 control points (L,R)
  40. inline float LinInterp( float frac, float L, float R )
  41. {
  42. return ( ( ( R - L ) * frac ) + L );
  43. }
  44. // bilinear interpolate between 4 control points (UL,UR,LL,LR)
  45. inline float BiLinInterp( float Xfrac, float Yfrac, float UL, float UR, float LL, float LR )
  46. {
  47. float iu = LinInterp( Xfrac, UL, UR );
  48. float il = LinInterp( Xfrac, LL, LR );
  49. return( LinInterp( Yfrac, iu, il ) );
  50. }
  51. // trilinear interpolate between 8 control points (ULN,URN,LLN,LRN,ULF,URF,LLF,LRF)
  52. inline float TriLinInterp( float Xfrac, float Yfrac, float Zfrac, float ULN,
  53. float URN, float LLN, float LRN, float ULF, float URF, float LLF, float LRF )
  54. {
  55. float iu = LinInterp( Xfrac, ULN, URN );
  56. float il = LinInterp( Xfrac, LLN, LRN );
  57. float jn =( LinInterp( Yfrac, iu, il ) );
  58. iu = LinInterp( Xfrac, ULF, URF );
  59. il = LinInterp( Xfrac, LLF, LRF );
  60. float jf =( LinInterp( Yfrac, iu, il ) );
  61. return( LinInterp( Zfrac, jn, jf ) );
  62. }
  63. static char GetChar( FileHandle_t & f )
  64. {
  65. char a;
  66. g_pFullFileSystem->Read( &a, 1, f );
  67. return a;
  68. }
  69. static int GetInt( FileHandle_t & f )
  70. {
  71. char buf[100];
  72. char * bout = buf;
  73. for( ; ; )
  74. {
  75. char c = GetChar( f );
  76. if ( ( c <'0' ) || ( c >'9' ) )
  77. break;
  78. *( bout++ ) = c;
  79. }
  80. *( bout++ ) = 0;
  81. return atoi( buf );
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Constructors
  85. //-----------------------------------------------------------------------------
  86. FloatBitMap_t::FloatBitMap_t( int nWidth, int nHeight, int nDepth, int nAttributeMask )
  87. {
  88. Init( nWidth, nHeight, nDepth, nAttributeMask );
  89. }
  90. FloatBitMap_t::FloatBitMap_t( const FloatBitMap_t *pOrig )
  91. {
  92. Init( pOrig->NumCols(), pOrig->NumRows(), pOrig->NumSlices() );
  93. LoadFromFloatBitmap( pOrig );
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Initialize, shutdown
  97. //-----------------------------------------------------------------------------
  98. void FloatBitMap_t::Shutdown()
  99. {
  100. Purge();
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Construct a floating point gamma table
  104. //-----------------------------------------------------------------------------
  105. static void ConstructFloatGammaTable( float* pTable, float flSrcGamma, float flDstGamma )
  106. {
  107. float flOO1023 = 1.0f / 1023.0f;
  108. for( int i = 0; i < 1024; i++ )
  109. {
  110. pTable[i] = pow( (float)i * flOO1023, flSrcGamma / flDstGamma );
  111. }
  112. }
  113. static void ConstructShortGammaTable( uint16* pTable, float flSrcGamma, float flDstGamma )
  114. {
  115. float flOO1023 = 1.0f / 1023.0f;
  116. for( int i = 0; i < 1024; i++ )
  117. {
  118. pTable[i] = ( uint16 )( 1023.0f * pow( (float)i * flOO1023, flSrcGamma / flDstGamma ) + 0.5f );
  119. }
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Gets the gamma table
  123. //-----------------------------------------------------------------------------
  124. static const float *GetFloatGammaTable( float flSrcGamma )
  125. {
  126. // Compute gamma tables...
  127. static float s_pGammaToLinear[1024];
  128. static float s_flLastSrcGamma = -1;
  129. if ( s_flLastSrcGamma != flSrcGamma )
  130. {
  131. ConstructFloatGammaTable( s_pGammaToLinear, flSrcGamma, 1.0f );
  132. s_flLastSrcGamma = flSrcGamma;
  133. }
  134. return s_pGammaToLinear;
  135. }
  136. static const uint16 *GetShortGammaTable( float flDestGamma )
  137. {
  138. // Compute gamma tables...
  139. static uint16 s_pLinearToGamma[1024];
  140. static float s_flLastDestGamma = -1;
  141. if ( s_flLastDestGamma != flDestGamma )
  142. {
  143. ConstructShortGammaTable( s_pLinearToGamma, 1.0f, flDestGamma );
  144. s_flLastDestGamma = flDestGamma;
  145. }
  146. return s_pLinearToGamma;
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Loads from a buffer, assumes dimensions match the bitmap size
  150. //-----------------------------------------------------------------------------
  151. void FloatBitMap_t::LoadFromBuffer( const void *pBuffer, size_t nBufSize, ImageFormat fmt, float flGamma )
  152. {
  153. if ( !pBuffer || !nBufSize )
  154. return;
  155. Assert( ImageLoader::GetMemRequired( NumCols(), NumRows(), NumSlices(), 1, fmt ) == (int)nBufSize );
  156. if( ImageLoader::GetMemRequired( NumCols(), NumRows(), NumSlices(), 1, fmt ) != (int)nBufSize )
  157. {
  158. Warning( "FloatBitMap_t::LoadFromBuffer: Received improper buffer size, skipping!\n" );
  159. return;
  160. }
  161. // Cache off constant values
  162. float c[FBM_ATTR_COUNT] = { 0.0 };
  163. int nMask = GetAttributeMask();
  164. for ( int i = 0; i < FBM_ATTR_COUNT; ++i )
  165. {
  166. if ( ( nMask & ( 1 << i ) ) == 0 )
  167. {
  168. c[i] = ConstantValue( i );
  169. }
  170. }
  171. switch( fmt )
  172. {
  173. case IMAGE_FORMAT_ABGR8888:
  174. LoadFromBufferRGBA( ( const ABGR8888_t* )pBuffer, nBufSize / sizeof(ABGR8888_t), GetFloatGammaTable( flGamma ) );
  175. break;
  176. case IMAGE_FORMAT_RGBA8888:
  177. LoadFromBufferRGBA( ( const RGBA8888_t* )pBuffer, nBufSize / sizeof(RGBA8888_t), GetFloatGammaTable( flGamma ) );
  178. break;
  179. case IMAGE_FORMAT_BGRA8888:
  180. LoadFromBufferRGBA( ( const BGRA8888_t* )pBuffer, nBufSize / sizeof(BGRA8888_t), GetFloatGammaTable( flGamma ) );
  181. break;
  182. case IMAGE_FORMAT_RGB888:
  183. LoadFromBufferRGB( ( const RGB888_t* )pBuffer, nBufSize / sizeof(RGB888_t), GetFloatGammaTable( flGamma ) );
  184. break;
  185. case IMAGE_FORMAT_BGR888:
  186. LoadFromBufferRGB( ( const BGR888_t* )pBuffer, nBufSize / sizeof(BGR888_t), GetFloatGammaTable( flGamma ) );
  187. break;
  188. case IMAGE_FORMAT_BGRX8888:
  189. LoadFromBufferRGB( ( BGRX8888_t* )pBuffer, nBufSize / sizeof(BGRX8888_t), GetFloatGammaTable( flGamma ) );
  190. break;
  191. case IMAGE_FORMAT_UV88:
  192. LoadFromBufferUV( ( const UV88_t* )pBuffer, nBufSize / sizeof(UV88_t) );
  193. break;
  194. case IMAGE_FORMAT_UVWQ8888:
  195. LoadFromBufferUVWQ( ( const UVWQ8888_t* )pBuffer, nBufSize / sizeof(UVWQ8888_t) );
  196. break;
  197. case IMAGE_FORMAT_UVLX8888:
  198. LoadFromBufferUVLX( ( const UVLX8888_t* )pBuffer, nBufSize / sizeof(UVLX8888_t) );
  199. break;
  200. default:
  201. Warning( "FloatBitMap_t::LoadFromBuffer: Unsupported color format, skipping!\n" );
  202. Assert( 0 );
  203. break;
  204. }
  205. // Restore constant values
  206. for ( int i = 0; i < FBM_ATTR_COUNT; ++i )
  207. {
  208. if ( ( nMask & ( 1 << i ) ) == 0 )
  209. {
  210. FillAttr( i, c[i] );
  211. }
  212. }
  213. }
  214. void FloatBitMap_t::LoadFromFloatBitmap( const FloatBitMap_t *pOrig )
  215. {
  216. Assert( ( NumCols() == pOrig->NumCols() ) && ( NumRows() == pOrig->NumRows() ) && ( NumSlices() == pOrig->NumSlices() ) );
  217. if ( ( NumCols() != pOrig->NumCols() ) || ( NumRows() != pOrig->NumRows() ) || ( NumSlices() != pOrig->NumSlices() ) )
  218. {
  219. Warning( "FloatBitMap_t::LoadFromFloatBitmap: Received improper bitmap size, skipping!\n" );
  220. return;
  221. }
  222. float flDefaultVal[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
  223. for ( int i = 0; i < 4; ++i )
  224. {
  225. if ( !HasAttributeData( (FBMAttribute_t)i ) )
  226. {
  227. FillAttr( i, flDefaultVal[i] );
  228. }
  229. else
  230. {
  231. CopyAttrFrom( *pOrig, i );
  232. }
  233. }
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Writes into a buffer, assumes dimensions match the bitmap size
  237. //-----------------------------------------------------------------------------
  238. void FloatBitMap_t::WriteToBuffer( void *pBuffer, size_t nBufSize, ImageFormat fmt, float flGamma ) const
  239. {
  240. if ( !pBuffer || !nBufSize )
  241. return;
  242. Assert( ImageLoader::GetMemRequired( NumCols(), NumRows(), NumSlices(), 1, fmt ) == (int)nBufSize );
  243. if( ImageLoader::GetMemRequired( NumCols(), NumRows(), NumSlices(), 1, fmt ) != (int)nBufSize )
  244. {
  245. Warning( "FloatBitMap_t::WriteToBuffer: Received improper buffer size, skipping!\n" );
  246. return;
  247. }
  248. switch( fmt )
  249. {
  250. case IMAGE_FORMAT_ABGR8888:
  251. WriteToBufferRGBA( ( ABGR8888_t* )pBuffer, nBufSize / sizeof(ABGR8888_t), GetShortGammaTable( flGamma ) );
  252. break;
  253. case IMAGE_FORMAT_RGBA8888:
  254. WriteToBufferRGBA( ( RGBA8888_t* )pBuffer, nBufSize / sizeof(RGBA8888_t), GetShortGammaTable( flGamma ) );
  255. break;
  256. case IMAGE_FORMAT_BGRA8888:
  257. WriteToBufferRGBA( ( BGRA8888_t* )pBuffer, nBufSize / sizeof(BGRA8888_t), GetShortGammaTable( flGamma ) );
  258. break;
  259. case IMAGE_FORMAT_RGB888:
  260. WriteToBufferRGB( ( RGB888_t* )pBuffer, nBufSize / sizeof(RGB888_t), GetShortGammaTable( flGamma ) );
  261. break;
  262. case IMAGE_FORMAT_BGR888:
  263. WriteToBufferRGB( ( BGR888_t* )pBuffer, nBufSize / sizeof(BGR888_t), GetShortGammaTable( flGamma ) );
  264. break;
  265. case IMAGE_FORMAT_BGRX8888:
  266. WriteToBufferRGB( ( BGRX8888_t* )pBuffer, nBufSize / sizeof(BGRX8888_t), GetShortGammaTable( flGamma ) );
  267. break;
  268. case IMAGE_FORMAT_UV88:
  269. WriteToBufferUV( ( UV88_t* )pBuffer, nBufSize / sizeof(UV88_t) );
  270. break;
  271. case IMAGE_FORMAT_UVWQ8888:
  272. WriteToBufferUVWQ( ( UVWQ8888_t* )pBuffer, nBufSize / sizeof(UVWQ8888_t) );
  273. break;
  274. case IMAGE_FORMAT_UVLX8888:
  275. WriteToBufferUVLX( ( UVLX8888_t* )pBuffer, nBufSize / sizeof(UVLX8888_t) );
  276. break;
  277. default:
  278. Warning( "FloatBitMap_t::WriteToBuffer: Unsupported color format, skipping!\n" );
  279. Assert( 0 );
  280. break;
  281. }
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Loads from a PSD file
  285. //-----------------------------------------------------------------------------
  286. bool FloatBitMap_t::LoadFromPSD( const char *pFilename )
  287. {
  288. Bitmap_t bitmap;
  289. CUtlStreamBuffer buf( pFilename, "GAME", CUtlBuffer::READ_ONLY );
  290. if ( IsPSDFile( buf ) )
  291. {
  292. if ( !PSDReadFileRGBA8888( buf, bitmap ) )
  293. return false;
  294. if ( bitmap.Format() != IMAGE_FORMAT_RGBA8888 )
  295. return false;
  296. }
  297. Init( bitmap.Width(), bitmap.Height() );
  298. for ( int x = 0; x < bitmap.Width(); x++ )
  299. {
  300. for ( int y = 0; y < bitmap.Height(); y++ )
  301. {
  302. RGBA8888_t* pPixel = (RGBA8888_t*)bitmap.GetPixel( x, y );
  303. Pixel( x, y, 0, 0 ) = pPixel->r / 255.0f;
  304. Pixel( x, y, 0, 1 ) = pPixel->g / 255.0f;
  305. Pixel( x, y, 0, 2 ) = pPixel->b / 255.0f;
  306. Pixel( x, y, 0, 3 ) = pPixel->a / 255.0f;
  307. }
  308. }
  309. return true;
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Loads from a PFM file
  313. //-----------------------------------------------------------------------------
  314. #define PFM_MAX_XSIZE 2048
  315. bool FloatBitMap_t::LoadFromPFM( const char* fname )
  316. {
  317. bool bSuccess = false;
  318. FileHandle_t f = g_pFullFileSystem->Open(fname, "rb");
  319. if ( !f )
  320. return false;
  321. if( ( GetChar( f ) == 'P' ) && ( GetChar( f ) == 'F' ) && ( GetChar( f ) == '\n' ) )
  322. {
  323. int nWidth = GetInt( f );
  324. int nHeight = GetInt( f );
  325. // eat crap until the next newline
  326. while( GetChar( f ) != '\n' )
  327. {
  328. }
  329. // printf("file %s w=%d h=%d\n",fname,Width,Height);
  330. Init( nWidth, nHeight );
  331. for( int y = nHeight - 1; y >= 0; y-- )
  332. {
  333. float linebuffer[PFM_MAX_XSIZE * 3];
  334. g_pFullFileSystem->Read( linebuffer, 3 * nWidth * sizeof( float ), f );
  335. for( int x = 0; x < nWidth; x++ )
  336. {
  337. for( int c = 0; c < 3; c++ )
  338. {
  339. Pixel( x, y, 0, c ) = linebuffer[x * 3 + c];
  340. }
  341. }
  342. }
  343. bSuccess = true;
  344. }
  345. g_pFullFileSystem->Close( f ); // close file after reading
  346. return bSuccess;
  347. }
  348. bool FloatBitMap_t::WritePFM( const char* fname )
  349. {
  350. FileHandle_t f = g_pFullFileSystem->Open(fname, "wb");
  351. if ( f )
  352. {
  353. g_pFullFileSystem->FPrintf( f, "PF\n%d %d\n-1.000000\n", NumCols(), NumRows());
  354. for( int y = NumRows() - 1; y >= 0; y-- )
  355. {
  356. float linebuffer[PFM_MAX_XSIZE * 3];
  357. for( int x = 0; x < NumCols(); x++ )
  358. {
  359. for( int c = 0; c < 3; c++ )
  360. {
  361. linebuffer[x * 3 + c]= Pixel( x, y, 0, c );
  362. }
  363. }
  364. g_pFullFileSystem->Write( linebuffer, 3 * NumCols() * sizeof( float ), f );
  365. }
  366. g_pFullFileSystem->Close( f );
  367. return true;
  368. }
  369. return false;
  370. }
  371. float FloatBitMap_t::InterpolatedPixel( float x, float y, int comp ) const
  372. {
  373. int Top = ( int )floor( y );
  374. float Yfrac = y - Top;
  375. int Bot = MIN( NumRows() - 1, Top + 1 );
  376. int Left = ( int )floor( x );
  377. float Xfrac = x - Left;
  378. int Right = MIN( NumCols() - 1, Left + 1 );
  379. return
  380. BiLinInterp( Xfrac, Yfrac,
  381. Pixel( Left, Top, 0, comp ),
  382. Pixel( Right, Top, 0, comp ),
  383. Pixel( Left, Bot, 0, comp ),
  384. Pixel( Right, Bot, 0, comp ) );
  385. }
  386. float FloatBitMap_t::InterpolatedPixel( float x, float y, float z, int comp ) const
  387. {
  388. int Top = ( int )floor( y );
  389. float Yfrac = y - Top;
  390. int Bot = MIN( NumRows() - 1, Top + 1 );
  391. int Left = ( int )floor( x );
  392. float Xfrac = x - Left;
  393. int Right = MIN( NumCols() - 1, Left + 1 );
  394. int Near = ( int )floor( z );
  395. float Zfrac = z - Near;
  396. int Far = MIN( NumSlices() - 1, Near + 1 );
  397. return
  398. TriLinInterp( Xfrac, Yfrac, Zfrac,
  399. Pixel( Left, Top, Near, comp ),
  400. Pixel( Right, Top, Near, comp ),
  401. Pixel( Left, Bot, Near, comp ),
  402. Pixel( Right, Bot, Near, comp ),
  403. Pixel( Left, Top, Far, comp ),
  404. Pixel( Right, Top, Far, comp ),
  405. Pixel( Left, Bot, Far, comp ),
  406. Pixel( Right, Bot, Far, comp ) );
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Method to slam a particular channel to always be the same value
  410. //-----------------------------------------------------------------------------
  411. void FloatBitMap_t::SetChannel( int comp, float flValue )
  412. {
  413. for ( int z = 0; z < NumSlices(); z++ )
  414. {
  415. for ( int y = 0; y < NumRows(); y++ )
  416. {
  417. for ( int x = 0; x < NumCols(); x++ )
  418. {
  419. Pixel( x, y, z, comp ) = flValue;
  420. }
  421. }
  422. }
  423. }
  424. //-----------------------------------------------------------------
  425. // resize (with bilinear filter) truecolor bitmap in place
  426. void FloatBitMap_t::ReSize( int NewWidth, int NewHeight )
  427. {
  428. float XRatio = ( float )NumCols() / ( float )NewWidth;
  429. float YRatio = ( float )NumRows() / ( float )NewHeight;
  430. float SourceX, SourceY, Xfrac, Yfrac;
  431. int Top, Bot, Left, Right;
  432. FloatBitMap_t newrgba( NewWidth, NewHeight );
  433. SourceY = 0;
  434. for( int y = 0; y < NewHeight; y++ )
  435. {
  436. Yfrac = SourceY - floor( SourceY );
  437. Top = ( int )SourceY;
  438. Bot = ( int )(SourceY + 1 );
  439. if ( Bot >= NumRows() )
  440. Bot = NumRows() - 1;
  441. SourceX = 0;
  442. for( int x = 0; x < NewWidth; x++ )
  443. {
  444. Xfrac = SourceX - floor( SourceX );
  445. Left = ( int )SourceX;
  446. Right = ( int )( SourceX + 1 );
  447. if ( Right >= NumCols() )
  448. Right = NumCols() - 1;
  449. for( int c = 0; c < 4; c++ )
  450. {
  451. newrgba.Pixel( x, y, 0, c ) = BiLinInterp( Xfrac, Yfrac,
  452. Pixel( Left, Top, 0, c ),
  453. Pixel( Right, Top, 0, c ),
  454. Pixel( Left, Bot, 0, c ),
  455. Pixel( Right, Bot, 0, c ) );
  456. }
  457. SourceX += XRatio;
  458. }
  459. SourceY += YRatio;
  460. }
  461. MoveDataFrom( newrgba );
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Makes the image be a sub-range of the current image
  465. //-----------------------------------------------------------------------------
  466. void FloatBitMap_t::Crop( int x1, int y1, int z1, int nWidth, int nHeight, int nDepth )
  467. {
  468. int x2 = x1 + nWidth;
  469. int y2 = y1 + nHeight;
  470. int z2 = z1 + nDepth;
  471. if ( ( x1 >= NumCols() || y1 >= NumRows() || z1 >= NumSlices() ) || ( x2 <= 0 || y2 <= 0 || z2 <= 0 ) )
  472. {
  473. Init( nWidth, nHeight, nDepth );
  474. return;
  475. }
  476. x1 = clamp( x1, 0, NumCols() );
  477. y1 = clamp( y1, 0, NumRows() );
  478. z1 = clamp( z1, 0, NumSlices() );
  479. x2 = clamp( x2, 0, NumCols() );
  480. y2 = clamp( y2, 0, NumRows() );
  481. z2 = clamp( z2, 0, NumSlices() );
  482. nWidth = x2 - x1; nHeight = y2 - y1; nDepth = z2 - z1;
  483. // Check for crops that don't require data movement
  484. if ( NumSlices() <= 1 )
  485. {
  486. if ( nWidth == NumCols() )
  487. {
  488. m_nRows = nHeight;
  489. return;
  490. }
  491. }
  492. else
  493. {
  494. if ( nWidth == NumCols() && nHeight == NumRows() )
  495. {
  496. m_nSlices = nDepth;
  497. return;
  498. }
  499. }
  500. // Generic data movement; works because data is stored in ascending
  501. // order in memory in the same way as we're looping over the data
  502. int ci[4];
  503. int nAttr = ComputeValidAttributeList( ci );
  504. for ( int z = 0; z < nDepth; ++z )
  505. {
  506. for ( int y = 0; y < nHeight; ++y )
  507. {
  508. for ( int x = 0; x < nWidth; ++x )
  509. {
  510. for ( int c = 0; c < nAttr; ++c )
  511. {
  512. Pixel( x, y, z, ci[c] ) = Pixel( x + x1, y + y1, z + z1, ci[c] );
  513. }
  514. }
  515. }
  516. }
  517. }
  518. struct TGAHeader_t
  519. {
  520. unsigned char id_length, colormap_type, image_type;
  521. unsigned char colormap_index0, colormap_index1, colormap_length0, colormap_length1;
  522. unsigned char colormap_size;
  523. unsigned char x_origin0, x_origin1, y_origin0, y_origin1, width0, width1, height0, height1;
  524. unsigned char pixel_size, attributes;
  525. };
  526. bool FloatBitMap_t::WriteTGAFile( const char* filename ) const
  527. {
  528. FileHandle_t f = g_pFullFileSystem->Open(filename, "wb");
  529. if ( f )
  530. {
  531. TGAHeader_t myheader;
  532. memset( & myheader, 0, sizeof( myheader ) );
  533. myheader.image_type = 2;
  534. myheader.pixel_size = 32;
  535. myheader.width0 = NumCols() & 0xff;
  536. myheader.width1 = ( NumCols() >> 8 );
  537. myheader.height0 = NumRows() & 0xff;
  538. myheader.height1 = ( NumRows() >> 8 );
  539. myheader.attributes = 0x20;
  540. g_pFullFileSystem->Write( & myheader, sizeof( myheader ), f );
  541. // now, write the pixels
  542. for( int y = 0; y < NumRows(); y++ )
  543. {
  544. for( int x = 0; x < NumCols(); x++ )
  545. {
  546. PixRGBAF fpix = PixelRGBAF( x, y, 0 );
  547. PixRGBA8 pix8 = PixRGBAF_to_8( fpix );
  548. g_pFullFileSystem->Write( & pix8.Blue, 1, f );
  549. g_pFullFileSystem->Write( & pix8.Green, 1, f );
  550. g_pFullFileSystem->Write( & pix8.Red, 1, f );
  551. g_pFullFileSystem->Write( & pix8.Alpha, 1, f );
  552. }
  553. }
  554. g_pFullFileSystem->Close( f ); // close file after reading
  555. return true;
  556. }
  557. return false;
  558. }
  559. FloatBitMap_t::FloatBitMap_t( const char* tgafilename )
  560. {
  561. // load from a tga or pfm or psd
  562. if ( Q_stristr( tgafilename, ".psd") )
  563. {
  564. LoadFromPSD( tgafilename );
  565. return;
  566. }
  567. if ( Q_stristr( tgafilename, ".pfm") )
  568. {
  569. LoadFromPFM( tgafilename );
  570. return;
  571. }
  572. int width1, height1;
  573. ImageFormat imageFormat1;
  574. float gamma1;
  575. if( !TGALoader::GetInfo( tgafilename, &width1, &height1, &imageFormat1, &gamma1 ) )
  576. {
  577. Warning( "FloatBitMap_t: Error opening %s\n", tgafilename );
  578. Init( 1, 1 );
  579. Pixel( 0, 0, 0, 0 ) = Pixel( 0, 0, 0, 3 ) = 1.0f;
  580. Pixel( 0, 0, 0, 1 ) = Pixel( 0, 0, 0, 2 ) = 0.0f;
  581. return;
  582. }
  583. Init( width1, height1 );
  584. uint8 * pImage1Tmp =
  585. new uint8 [ImageLoader::GetMemRequired( width1, height1, 1, imageFormat1, false )];
  586. if( !TGALoader::Load( pImage1Tmp, tgafilename, width1, height1, imageFormat1, 2.2f, false ) )
  587. {
  588. Warning( "FloatBitMap_t: Error loading %s\n", tgafilename );
  589. Init( 1, 1 );
  590. Pixel( 0, 0, 0, 0 ) = Pixel( 0, 0, 0, 3 ) = 1.0f;
  591. Pixel( 0, 0, 0, 1 ) = Pixel( 0, 0, 0, 2 ) = 0.0f;
  592. delete[] pImage1Tmp;
  593. return;
  594. }
  595. uint8 * pImage1 =
  596. new uint8 [ImageLoader::GetMemRequired( width1, height1, 1, IMAGE_FORMAT_ABGR8888, false )];
  597. ImageLoader::ConvertImageFormat( pImage1Tmp, imageFormat1, pImage1, IMAGE_FORMAT_ABGR8888, width1, height1, 0, 0 );
  598. for( int y = 0; y < height1; y++ )
  599. {
  600. for( int x = 0; x < width1; x++ )
  601. {
  602. for( int c = 0; c < 4; c++ )
  603. {
  604. Pixel( x, y, 0, 3 - c ) = pImage1[c + 4 * ( x + ( y * width1 ) )]/ 255.0;
  605. }
  606. }
  607. }
  608. delete[] pImage1;
  609. delete[] pImage1Tmp;
  610. }
  611. //-----------------------------------------------------------------------------
  612. // Downsample using bilinear filtering
  613. //-----------------------------------------------------------------------------
  614. void FloatBitMap_t::QuarterSize2D( FloatBitMap_t *pDest, int nStart, int nCount )
  615. {
  616. for( int y = nStart; y < nStart + nCount; y++ )
  617. {
  618. for( int x = 0; x < pDest->NumCols(); x++ )
  619. {
  620. for( int c = 0; c < 4; c++ )
  621. {
  622. pDest->Pixel( x, y, 0, c ) =
  623. ( ( Pixel( x * 2, y * 2, 0, c ) + Pixel( x * 2 + 1, y * 2, 0, c ) +
  624. Pixel( x * 2, y * 2 + 1, 0, c ) + Pixel( x * 2 + 1, y * 2 + 1, 0, c ) ) / 4.0f );
  625. }
  626. }
  627. }
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Downsample using trilinear filtering
  631. //-----------------------------------------------------------------------------
  632. void FloatBitMap_t::QuarterSize3D( FloatBitMap_t *pDest, int nStart, int nCount )
  633. {
  634. for( int z = nStart; z < nStart + nCount; z++ )
  635. {
  636. for( int y = 0; y < pDest->NumRows(); y++ )
  637. {
  638. for( int x = 0; x < pDest->NumCols(); x++ )
  639. {
  640. for( int c = 0; c < 4; c++ )
  641. {
  642. pDest->Pixel( x, y, z, c ) =
  643. ( ( Pixel( x * 2, y * 2, z * 2, c ) + Pixel( x * 2 + 1, y * 2, z * 2, c ) +
  644. Pixel( x * 2, y * 2 + 1,z * 2, c ) + Pixel( x * 2 + 1, y * 2 + 1,z * 2, c ) +
  645. Pixel( x * 2, y * 2, z * 2 + 1, c ) + Pixel( x * 2 + 1, y * 2, z * 2 + 1, c ) +
  646. Pixel( x * 2, y * 2 + 1,z * 2 + 1, c ) + Pixel( x * 2 + 1, y * 2 + 1,z * 2 + 1, c ) ) / 8.0f );
  647. }
  648. }
  649. }
  650. }
  651. }
  652. void FloatBitMap_t::QuarterSize( FloatBitMap_t *pBitmap )
  653. {
  654. // generate a new bitmap half on each axis
  655. bool bIs2D = ( NumSlices() == 1 );
  656. int sx = NumCols() / 2;
  657. int sy = NumRows() / 2;
  658. int sz = NumSlices() / 2;
  659. sx = MAX( sx, 1 );
  660. sy = MAX( sy, 1 );
  661. sz = MAX( sz, 1 );
  662. pBitmap->Init( sx, sy, sz );
  663. if ( bIs2D )
  664. {
  665. ParallelLoopProcessChunks( sm_pFBMThreadPool, pBitmap, 0, sy, 16, this, &FloatBitMap_t::QuarterSize2D );
  666. }
  667. else
  668. {
  669. ParallelLoopProcessChunks( sm_pFBMThreadPool, pBitmap, 0, sz, 8, this, &FloatBitMap_t::QuarterSize3D );
  670. }
  671. }
  672. //-----------------------------------------------------------------------------
  673. // Downsample using bilinear filtering
  674. //-----------------------------------------------------------------------------
  675. void FloatBitMap_t::QuarterSizeBlocky2D( FloatBitMap_t *pDest, int nStart, int nCount )
  676. {
  677. for( int y = nStart; y < nStart + nCount; y++ )
  678. {
  679. for( int x = 0; x < pDest->NumCols(); x++ )
  680. {
  681. for( int c = 0; c < 4; c++ )
  682. {
  683. pDest->Pixel( x, y, 0, c ) = Pixel( x * 2, y * 2, 0, c );
  684. }
  685. }
  686. }
  687. }
  688. //-----------------------------------------------------------------------------
  689. // Downsample using trilinear filtering
  690. //-----------------------------------------------------------------------------
  691. void FloatBitMap_t::QuarterSizeBlocky3D( FloatBitMap_t *pDest, int nStart, int nCount )
  692. {
  693. for( int z = nStart; z < nStart + nCount; z++ )
  694. {
  695. for( int y = 0; y < pDest->NumRows(); y++ )
  696. {
  697. for( int x = 0; x < pDest->NumCols(); x++ )
  698. {
  699. for( int c = 0; c < 4; c++ )
  700. {
  701. pDest->Pixel( x, y, z, c ) = Pixel( x * 2, y * 2, z * 2, c );
  702. }
  703. }
  704. }
  705. }
  706. }
  707. //-----------------------------------------------------------------------------
  708. // Downsample using point sampling
  709. //-----------------------------------------------------------------------------
  710. void FloatBitMap_t::QuarterSizeBlocky( FloatBitMap_t *pBitmap )
  711. {
  712. // generate a new bitmap half on each axis
  713. int sx = NumCols() / 2;
  714. int sy = NumRows() / 2;
  715. int sz = NumSlices() / 2;
  716. sx = MAX( sx, 1 );
  717. sy = MAX( sy, 1 );
  718. sz = MAX( sz, 1 );
  719. pBitmap->Init( sx, sy, sz );
  720. if ( NumSlices() == 1 )
  721. {
  722. ParallelLoopProcessChunks( sm_pFBMThreadPool, pBitmap, 0, sy, 128, this, &FloatBitMap_t::QuarterSizeBlocky2D );
  723. }
  724. else
  725. {
  726. ParallelLoopProcessChunks( sm_pFBMThreadPool, pBitmap, 0, sz, 32, this, &FloatBitMap_t::QuarterSizeBlocky3D );
  727. }
  728. }
  729. enum KernelType_t
  730. {
  731. KERNEL_DEFAULT = 0,
  732. KERNEL_ALPHATEST,
  733. };
  734. struct FloatBitmapResampleInfo_t
  735. {
  736. FloatBitMap_t *m_pSrcBitmap;
  737. FloatBitMap_t *m_pDestBitmap;
  738. const KernelInfo_t *m_pKernel;
  739. float *m_pAlphaResult;
  740. int m_nFlags;
  741. int m_nSrcWidth;
  742. int m_nSrcHeight;
  743. int m_nSrcDepth;
  744. float m_flAlphaThreshhold;
  745. float m_flAlphaHiFreqThreshhold;
  746. int m_nWRatio;
  747. int m_nHRatio;
  748. int m_nDRatio;
  749. };
  750. typedef void (*ApplyKernelFunc_t)( FloatBitmapResampleInfo_t *pInfo, int nStart, int nCount );
  751. //-----------------------------------------------------------------------------
  752. // Apply Kernel to an image
  753. //-----------------------------------------------------------------------------
  754. template< int type, bool bIsPowerOfTwo >
  755. class CKernelWrapper
  756. {
  757. public:
  758. static inline int ActualX( int x, FloatBitmapResampleInfo_t *pInfo )
  759. {
  760. if ( pInfo->m_nFlags & DOWNSAMPLE_CLAMPS )
  761. return clamp( x, 0, pInfo->m_nSrcWidth - 1 );
  762. // This works since pInfo->m_nSrcWidth is a power of two.
  763. // Even for negative #s!
  764. if ( bIsPowerOfTwo )
  765. return x & (pInfo->m_nSrcWidth - 1);
  766. return x % pInfo->m_nSrcWidth;
  767. }
  768. static inline int ActualY( int y, FloatBitmapResampleInfo_t *pInfo )
  769. {
  770. if ( pInfo->m_nFlags & DOWNSAMPLE_CLAMPT )
  771. return clamp( y, 0, pInfo->m_nSrcHeight - 1 );
  772. // This works since pInfo->m_nSrcHeight is a power of two.
  773. // Even for negative #s!
  774. if ( bIsPowerOfTwo )
  775. return y & (pInfo->m_nSrcHeight - 1);
  776. return y % pInfo->m_nSrcHeight;
  777. }
  778. static inline int ActualZ( int z, FloatBitmapResampleInfo_t *pInfo )
  779. {
  780. if ( pInfo->m_nFlags & DOWNSAMPLE_CLAMPU )
  781. return clamp( z, 0, pInfo->m_nSrcDepth - 1 );
  782. // This works since pInfo->m_nSrcDepth is a power of two.
  783. // Even for negative #s!
  784. if ( bIsPowerOfTwo )
  785. return z & (pInfo->m_nSrcDepth - 1);
  786. return z % pInfo->m_nSrcDepth;
  787. }
  788. static void ComputeWeightedAverageColor( FloatBitmapResampleInfo_t *pInfo,
  789. int startX, int startY, int startZ, float *total )
  790. {
  791. total[0] = total[1] = total[2] = total[3] = 0.0f;
  792. for ( int j = 0, srcZ = startZ; j < pInfo->m_pKernel->m_nDepth; ++j, ++srcZ )
  793. {
  794. int sz = ActualZ( srcZ, pInfo );
  795. for ( int k = 0, srcY = startY; k < pInfo->m_pKernel->m_nHeight; ++k, ++srcY )
  796. {
  797. int sy = ActualY( srcY, pInfo );
  798. int kernelIdx = pInfo->m_pKernel->m_nWidth * ( k + j * pInfo->m_pKernel->m_nHeight );
  799. for ( int l = 0, srcX = startX; l < pInfo->m_pKernel->m_nWidth; ++l, ++srcX, ++kernelIdx )
  800. {
  801. int sx = ActualX( srcX, pInfo );
  802. float flKernelFactor = pInfo->m_pKernel->m_pKernel[kernelIdx];
  803. if ( flKernelFactor == 0.0f )
  804. continue;
  805. total[FBM_ATTR_RED] += flKernelFactor * pInfo->m_pSrcBitmap->Pixel( sx, sy, sz, FBM_ATTR_RED );
  806. total[FBM_ATTR_GREEN] += flKernelFactor * pInfo->m_pSrcBitmap->Pixel( sx, sy, sz, FBM_ATTR_GREEN );
  807. total[FBM_ATTR_BLUE] += flKernelFactor * pInfo->m_pSrcBitmap->Pixel( sx, sy, sz, FBM_ATTR_BLUE );
  808. if ( type != KERNEL_ALPHATEST )
  809. {
  810. total[FBM_ATTR_ALPHA] += flKernelFactor * pInfo->m_pSrcBitmap->Pixel( sx, sy, sz, FBM_ATTR_ALPHA );
  811. }
  812. else
  813. {
  814. if ( pInfo->m_pSrcBitmap->Pixel( sx, sy, sz, FBM_ATTR_ALPHA ) > ( 192.0f / 255.0f ) )
  815. {
  816. total[FBM_ATTR_ALPHA] += flKernelFactor;
  817. }
  818. }
  819. }
  820. }
  821. }
  822. }
  823. static void AddAlphaToAlphaResult( FloatBitmapResampleInfo_t *pInfo,
  824. int startX, int startY, int startZ, float flAlpha, float *pAlphaResult )
  825. {
  826. for ( int j = 0, srcZ = startZ; j < pInfo->m_pKernel->m_nDepth; ++j, ++srcZ )
  827. {
  828. int sz = ActualZ( srcZ, pInfo );
  829. sz *= pInfo->m_nSrcWidth * pInfo->m_nSrcHeight;
  830. for ( int k = 0, srcY = startY; k < pInfo->m_pKernel->m_nHeight; ++k, ++srcY )
  831. {
  832. int sy = ActualY( srcY, pInfo );
  833. sy *= pInfo->m_nSrcWidth;
  834. int kernelIdx = k * pInfo->m_pKernel->m_nWidth + j * pInfo->m_pKernel->m_nWidth * pInfo->m_pKernel->m_nHeight;
  835. for ( int l = 0, srcX = startX; l < pInfo->m_pKernel->m_nWidth; ++l, ++srcX, ++kernelIdx )
  836. {
  837. int sx = ActualX( srcX, pInfo );
  838. int srcPixel = sz + sy + sx;
  839. float flKernelFactor = pInfo->m_pKernel->m_pInvKernel[kernelIdx];
  840. if ( flKernelFactor == 0.0f )
  841. continue;
  842. pAlphaResult[srcPixel] += flKernelFactor * flAlpha;
  843. }
  844. }
  845. }
  846. }
  847. static void AdjustAlphaChannel( FloatBitmapResampleInfo_t *pInfo, float *pAlphaResult )
  848. {
  849. // Find the delta between the alpha + source image
  850. int i, k;
  851. int nDstPixel = 0;
  852. for ( k = 0; k < pInfo->m_nSrcDepth; ++k )
  853. {
  854. for ( i = 0; i < pInfo->m_nSrcHeight; ++i )
  855. {
  856. for ( int j = 0; j < pInfo->m_nSrcWidth; ++j, ++nDstPixel )
  857. {
  858. pAlphaResult[nDstPixel] = fabs( pAlphaResult[nDstPixel] - pInfo->m_pSrcBitmap->Pixel( j, i, k, FBM_ATTR_ALPHA ) );
  859. }
  860. }
  861. }
  862. // Apply the kernel to the image
  863. int nInitialZ = ( pInfo->m_nDRatio > 1 ) ? (pInfo->m_nDRatio >> 1) - ((pInfo->m_nDRatio * pInfo->m_pKernel->m_nDiameter) >> 1) : 0;
  864. int nInitialY = ( pInfo->m_nHRatio > 1 ) ? (pInfo->m_nHRatio >> 1) - ((pInfo->m_nHRatio * pInfo->m_pKernel->m_nDiameter) >> 1) : 0;
  865. int nInitialX = ( pInfo->m_nWRatio > 1 ) ? (pInfo->m_nWRatio >> 1) - ((pInfo->m_nWRatio * pInfo->m_pKernel->m_nDiameter) >> 1) : 0;
  866. float flInvFactor = 1.0f;
  867. if ( pInfo->m_nDRatio != 0 )
  868. flInvFactor *= pInfo->m_nDRatio;
  869. if ( pInfo->m_nHRatio != 0 )
  870. flInvFactor *= pInfo->m_nHRatio;
  871. if ( pInfo->m_nWRatio != 0 )
  872. flInvFactor *= pInfo->m_nWRatio;
  873. flInvFactor = 1.0f / flInvFactor;
  874. for ( int h = 0; h < pInfo->m_pDestBitmap->NumSlices(); ++h )
  875. {
  876. int startZ = pInfo->m_nDRatio * h + nInitialZ;
  877. for ( i = 0; i < pInfo->m_pDestBitmap->NumRows(); ++i )
  878. {
  879. int startY = pInfo->m_nHRatio * i + nInitialY;
  880. for ( int j = 0; j < pInfo->m_pDestBitmap->NumCols(); ++j )
  881. {
  882. if ( pInfo->m_pDestBitmap->Pixel( j, i, h, FBM_ATTR_ALPHA ) == 1.0f )
  883. continue;
  884. int startX = pInfo->m_nWRatio * j + nInitialX;
  885. float flAlphaDelta = 0.0f;
  886. for ( int m = 0, srcZ = startZ; m < pInfo->m_nDRatio; ++m, ++srcZ )
  887. {
  888. int sz = ActualZ( srcZ, pInfo );
  889. sz *= pInfo->m_nSrcWidth * pInfo->m_nSrcHeight;
  890. for ( int k = 0, srcY = startY; k < pInfo->m_nHRatio; ++k, ++srcY )
  891. {
  892. int sy = ActualY( srcY, pInfo );
  893. sy *= pInfo->m_nSrcWidth;
  894. for ( int l = 0, srcX = startX; l < pInfo->m_nWRatio; ++l, ++srcX )
  895. {
  896. // HACK: This temp variable fixes an internal compiler error in vs2005
  897. int temp = srcX;
  898. int sx = ActualX( temp, pInfo );
  899. int srcPixel = sz + sy + sx;
  900. flAlphaDelta += pAlphaResult[srcPixel];
  901. }
  902. }
  903. }
  904. flAlphaDelta *= flInvFactor;
  905. if ( flAlphaDelta > pInfo->m_flAlphaHiFreqThreshhold )
  906. {
  907. pInfo->m_pDestBitmap->Pixel( j, i, h, FBM_ATTR_ALPHA ) = 1.0f;
  908. }
  909. }
  910. }
  911. }
  912. }
  913. static void ApplyKernel( FloatBitmapResampleInfo_t *pInfo, int nStart, int nCount )
  914. {
  915. // Apply the kernel to the image
  916. int nInitialZ = ( pInfo->m_nDRatio > 1 ) ? (pInfo->m_nDRatio >> 1) - ((pInfo->m_nDRatio * pInfo->m_pKernel->m_nDiameter) >> 1) : 0;
  917. int nInitialY = ( pInfo->m_nHRatio > 1 ) ? (pInfo->m_nHRatio >> 1) - ((pInfo->m_nHRatio * pInfo->m_pKernel->m_nDiameter) >> 1) : 0;
  918. int nInitialX = ( pInfo->m_nWRatio > 1 ) ? (pInfo->m_nWRatio >> 1) - ((pInfo->m_nWRatio * pInfo->m_pKernel->m_nDiameter) >> 1) : 0;
  919. int dw = pInfo->m_pDestBitmap->NumCols();
  920. int dh = pInfo->m_pDestBitmap->NumRows();
  921. int dd = pInfo->m_pDestBitmap->NumSlices();
  922. int sk, ek, si, ei;
  923. if ( dd == 1 )
  924. {
  925. sk = 0; ek = dd; si = nStart; ei = nStart + nCount;
  926. }
  927. else
  928. {
  929. sk = nStart; ek = nStart + nCount; si = 0; ei = dh;
  930. }
  931. for ( int k = sk; k < ek; ++k )
  932. {
  933. int startZ = pInfo->m_nDRatio * k + nInitialZ;
  934. for ( int i = si; i < ei; ++i )
  935. {
  936. int startY = pInfo->m_nHRatio * i + nInitialY;
  937. for ( int j = 0; j < dw; ++j )
  938. {
  939. int startX = pInfo->m_nWRatio * j + nInitialX;
  940. float total[4];
  941. ComputeWeightedAverageColor( pInfo, startX, startY, startZ, total );
  942. // NOTE: Can't use a table here, we lose too many bits
  943. if( type != KERNEL_ALPHATEST )
  944. {
  945. for ( int ch = 0; ch < 4; ++ ch )
  946. {
  947. pInfo->m_pDestBitmap->Pixel( j, i, k, ch ) = clamp( total[ch], 0.0f, 1.0f );
  948. }
  949. }
  950. else
  951. {
  952. // If there's more than 40% coverage, then keep the pixel (renormalize the color based on coverage)
  953. float flAlpha = ( total[3] >= pInfo->m_flAlphaThreshhold ) ? 1.0f : 0.0f;
  954. for ( int ch = 0; ch < 3; ++ ch )
  955. {
  956. pInfo->m_pDestBitmap->Pixel( j, i, k, ch ) = clamp( total[ch], 0.0f, 1.0f );
  957. }
  958. pInfo->m_pDestBitmap->Pixel( j, i, k, FBM_ATTR_ALPHA ) = clamp( flAlpha, 0.0f, 1.0f );
  959. AddAlphaToAlphaResult( pInfo, startX, startY, startZ, flAlpha, pInfo->m_pAlphaResult );
  960. }
  961. }
  962. }
  963. }
  964. if ( type == KERNEL_ALPHATEST )
  965. {
  966. AdjustAlphaChannel( pInfo, pInfo->m_pAlphaResult );
  967. }
  968. }
  969. };
  970. typedef CKernelWrapper< KERNEL_DEFAULT, false > ApplyKernelDefault_t;
  971. typedef CKernelWrapper< KERNEL_ALPHATEST, false > ApplyKernelAlphatest_t;
  972. typedef CKernelWrapper< KERNEL_DEFAULT, true > ApplyKernelDefaultPow2_t;
  973. typedef CKernelWrapper< KERNEL_ALPHATEST, true > ApplyKernelAlphatestPow2_t;
  974. static ApplyKernelFunc_t g_KernelFunc[] =
  975. {
  976. ApplyKernelDefault_t::ApplyKernel,
  977. ApplyKernelAlphatest_t::ApplyKernel,
  978. };
  979. static ApplyKernelFunc_t g_KernelFuncPow2[] =
  980. {
  981. ApplyKernelDefaultPow2_t::ApplyKernel,
  982. ApplyKernelAlphatestPow2_t::ApplyKernel,
  983. };
  984. //-----------------------------------------------------------------------------
  985. // Downsample using specified kernel (NOTE: Dest bitmap needs to have been initialized w/ final size)
  986. //-----------------------------------------------------------------------------
  987. void FloatBitMap_t::DownsampleNiceFiltered( const DownsampleInfo_t& downsampleInfo, FloatBitMap_t *pDestBitmap )
  988. {
  989. FloatBitmapResampleInfo_t info;
  990. info.m_nFlags = downsampleInfo.m_nFlags;
  991. info.m_pSrcBitmap = this;
  992. info.m_pDestBitmap = pDestBitmap;
  993. info.m_nWRatio = NumCols() / pDestBitmap->NumCols();
  994. info.m_nHRatio = NumRows() / pDestBitmap->NumRows();
  995. info.m_nDRatio = NumSlices() / pDestBitmap->NumSlices();
  996. info.m_nSrcWidth = NumCols();
  997. info.m_nSrcHeight = NumRows();
  998. info.m_nSrcDepth = NumSlices();
  999. info.m_flAlphaThreshhold = ( downsampleInfo.m_flAlphaThreshhold >= 0.0f ) ? downsampleInfo.m_flAlphaThreshhold : 0.4f;
  1000. info.m_flAlphaHiFreqThreshhold = ( downsampleInfo.m_flAlphaHiFreqThreshhold >= 0.0f ) ? downsampleInfo.m_flAlphaHiFreqThreshhold : 0.4f;
  1001. info.m_pAlphaResult = NULL;
  1002. KernelInfo_t kernel;
  1003. ImageLoader::ComputeNiceFilterKernel( info.m_nWRatio, info.m_nHRatio, info.m_nDRatio, &kernel );
  1004. info.m_pKernel = &kernel;
  1005. bool bIsPowerOfTwo = IsPowerOfTwo( info.m_nSrcWidth ) && IsPowerOfTwo( info.m_nSrcHeight ) && IsPowerOfTwo( info.m_nSrcDepth );
  1006. KernelType_t type;
  1007. if ( downsampleInfo.m_nFlags & DOWNSAMPLE_ALPHATEST )
  1008. {
  1009. int nSize = info.m_nSrcHeight * info.m_nSrcWidth * info.m_nSrcDepth * sizeof(float);
  1010. info.m_pAlphaResult = (float*)malloc( nSize );
  1011. memset( info.m_pAlphaResult, 0, nSize );
  1012. type = KERNEL_ALPHATEST;
  1013. }
  1014. else
  1015. {
  1016. type = KERNEL_DEFAULT;
  1017. }
  1018. int nCount, nChunkSize;
  1019. if ( info.m_nDRatio == 1 )
  1020. {
  1021. nCount = pDestBitmap->NumRows();
  1022. nChunkSize = 16;
  1023. }
  1024. else
  1025. {
  1026. nCount = pDestBitmap->NumSlices();
  1027. nChunkSize = 8;
  1028. }
  1029. if ( bIsPowerOfTwo )
  1030. {
  1031. ParallelLoopProcessChunks( sm_pFBMThreadPool, &info, 0, nCount, nChunkSize, g_KernelFuncPow2[type] );
  1032. }
  1033. else
  1034. {
  1035. ParallelLoopProcessChunks( sm_pFBMThreadPool, &info, 0, nCount, nChunkSize, g_KernelFunc[type] );
  1036. }
  1037. if ( info.m_pAlphaResult )
  1038. {
  1039. free( info.m_pAlphaResult );
  1040. }
  1041. ImageLoader::CleanupNiceFilterKernel( &kernel );
  1042. }
  1043. Vector FloatBitMap_t::AverageColor( void )
  1044. {
  1045. Vector ret( 0, 0, 0 );
  1046. for( int y = 0; y < NumRows(); y++ )
  1047. for( int x = 0; x < NumCols(); x++ )
  1048. for( int c = 0; c < 3; c++ )
  1049. ret[c]+= Pixel( x, y, 0, c );
  1050. ret *= 1.0 / ( NumCols() * NumRows() );
  1051. return ret;
  1052. }
  1053. float FloatBitMap_t::BrightestColor( void )
  1054. {
  1055. float ret = 0.0;
  1056. for( int y = 0; y < NumRows(); y++ )
  1057. for( int x = 0; x < NumCols(); x++ )
  1058. {
  1059. Vector v( Pixel( x, y, 0, 0 ), Pixel( x, y, 0, 1 ), Pixel( x, y, 0, 2 ) );
  1060. ret = MAX( ret, v.Length() );
  1061. }
  1062. return ret;
  1063. }
  1064. template < class T > static inline void SWAP( T & a, T & b )
  1065. {
  1066. T temp = a;
  1067. a = b;
  1068. b = temp;
  1069. }
  1070. void FloatBitMap_t::RaiseToPower( float power )
  1071. {
  1072. for( int y = 0; y < NumRows(); y++ )
  1073. for( int x = 0; x < NumCols(); x++ )
  1074. for( int c = 0; c < 3; c++ )
  1075. Pixel( x, y, 0, c ) = pow( ( float )MAX( 0.0, Pixel( x, y, 0, c ) ), ( float )power );
  1076. }
  1077. void FloatBitMap_t::Logize( void )
  1078. {
  1079. for( int y = 0; y < NumRows(); y++ )
  1080. for( int x = 0; x < NumCols(); x++ )
  1081. for( int c = 0; c < 3; c++ )
  1082. Pixel( x, y, 0, c ) = log( 1.0 + Pixel( x, y, 0, c ) );
  1083. }
  1084. void FloatBitMap_t::UnLogize( void )
  1085. {
  1086. for( int y = 0; y < NumRows(); y++ )
  1087. for( int x = 0; x < NumCols(); x++ )
  1088. for( int c = 0; c < 3; c++ )
  1089. Pixel( x, y, 0, c ) = exp( Pixel( x, y, 0, c ) ) - 1;
  1090. }
  1091. void FloatBitMap_t::Clear( float r, float g, float b, float a )
  1092. {
  1093. for ( int z = 0; z < NumSlices(); ++z )
  1094. {
  1095. for( int y = 0; y < NumRows(); y++ )
  1096. {
  1097. for( int x = 0; x < NumCols(); x++ )
  1098. {
  1099. Pixel( x, y, z, 0 ) = r;
  1100. Pixel( x, y, z, 1 ) = g;
  1101. Pixel( x, y, z, 2 ) = b;
  1102. Pixel( x, y, z, 3 ) = a;
  1103. }
  1104. }
  1105. }
  1106. }
  1107. void FloatBitMap_t::ScaleRGB( float scale_factor )
  1108. {
  1109. for( int y = 0; y < NumRows(); y++ )
  1110. for( int x = 0; x < NumCols(); x++ )
  1111. for( int c = 0; c < 3; c++ )
  1112. Pixel( x, y, 0, c ) *= scale_factor;
  1113. }
  1114. static int dx[4]={0, - 1, 1, 0};
  1115. static int dy[4]={- 1, 0, 0, 1};
  1116. #define NDELTAS 4
  1117. void FloatBitMap_t::SmartPaste( const FloatBitMap_t & b, int xofs, int yofs, uint32 Flags )
  1118. {
  1119. // now, need to make Difference map
  1120. FloatBitMap_t DiffMap0( this );
  1121. FloatBitMap_t DiffMap1( this );
  1122. FloatBitMap_t DiffMap2( this );
  1123. FloatBitMap_t DiffMap3( this );
  1124. FloatBitMap_t * deltas[4]={& DiffMap0, & DiffMap1, & DiffMap2, & DiffMap3};
  1125. for( int x = 0; x < NumCols(); x++ )
  1126. for( int y = 0; y < NumRows(); y++ )
  1127. for( int c = 0; c < 3; c++ )
  1128. {
  1129. for( int i = 0; i < NDELTAS; i++ )
  1130. {
  1131. int x1 = x + dx[i];
  1132. int y1 = y + dy[i];
  1133. x1 = MAX( 0, x1 );
  1134. x1 = MIN( NumCols() - 1, x1 );
  1135. y1 = MAX( 0, y1 );
  1136. y1 = MIN( NumRows() - 1, y1 );
  1137. float dx1 = Pixel( x, y, 0, c ) - Pixel( x1, y1, 0, c );
  1138. deltas[i]-> Pixel( x, y, 0, c ) = dx1;
  1139. }
  1140. }
  1141. for( int x = 1; x < b.NumCols() - 1; x++ )
  1142. for( int y = 1; y < b.NumRows() - 1; y++ )
  1143. for( int c = 0; c < 3; c++ )
  1144. {
  1145. for( int i = 0; i < NDELTAS; i++ )
  1146. {
  1147. float diff = b.Pixel( x, y, 0, c ) - b.Pixel( x + dx[i], y + dy[i], 0, c );
  1148. deltas[i]-> Pixel( x + xofs, y + yofs, 0, c ) = diff;
  1149. if ( Flags & SPFLAGS_MAXGRADIENT )
  1150. {
  1151. float dx1 = Pixel( x + xofs, y + yofs, 0, c ) - Pixel( x + dx[i]+ xofs, y + dy[i]+ yofs, 0, c );
  1152. if ( fabs( dx1 ) > fabs( diff ) )
  1153. deltas[i]-> Pixel( x + xofs, y + yofs, 0, c ) = dx1;
  1154. }
  1155. }
  1156. }
  1157. // now, calculate modifiability
  1158. for( int x = 0; x < NumCols(); x++ )
  1159. for( int y = 0; y < NumRows(); y++ )
  1160. {
  1161. float modify = 0;
  1162. if (
  1163. ( x > xofs + 1 ) && ( x <= xofs + b.NumCols() - 2 ) &&
  1164. ( y > yofs + 1 ) && ( y <= yofs + b.NumRows() - 2 ) )
  1165. modify = 1;
  1166. Alpha( x, y, 0 ) = modify;
  1167. }
  1168. // // now, force a fex pixels in center to be constant
  1169. // int midx=xofs+b.Width/2;
  1170. // int midy=yofs+b.Height/2;
  1171. // for(x=midx-10;x<midx+10;x++)
  1172. // for(int y=midy-10;y<midy+10;y++)
  1173. // {
  1174. // Alpha(x,y)=0;
  1175. // for(int c=0;c<3;c++)
  1176. // Pixel(x,y,c)=b.Pixel(x-xofs,y-yofs,c);
  1177. // }
  1178. Poisson( deltas, 6000, Flags );
  1179. }
  1180. void FloatBitMap_t::ScaleGradients( void )
  1181. {
  1182. // now, need to make Difference map
  1183. FloatBitMap_t DiffMap0( this );
  1184. FloatBitMap_t DiffMap1( this );
  1185. FloatBitMap_t DiffMap2( this );
  1186. FloatBitMap_t DiffMap3( this );
  1187. FloatBitMap_t * deltas[4]={& DiffMap0, & DiffMap1, & DiffMap2, & DiffMap3};
  1188. double gsum = 0.0;
  1189. for( int x = 0; x < NumCols(); x++ )
  1190. for( int y = 0; y < NumRows(); y++ )
  1191. for( int c = 0; c < 3; c++ )
  1192. {
  1193. for( int i = 0; i < NDELTAS; i++ )
  1194. {
  1195. int x1 = x + dx[i];
  1196. int y1 = y + dy[i];
  1197. x1 = MAX( 0, x1 );
  1198. x1 = MIN( NumCols() - 1, x1 );
  1199. y1 = MAX( 0, y1 );
  1200. y1 = MIN( NumRows() - 1, y1 );
  1201. float dx1 = Pixel( x, y, 0, c ) - Pixel( x1, y1, 0, c );
  1202. deltas[i]-> Pixel( x, y, 0, c ) = dx1;
  1203. gsum += fabs( dx1 );
  1204. }
  1205. }
  1206. // now, reduce gradient changes
  1207. // float gavg=gsum/(NumCols()*NumRows());
  1208. for( int x = 0; x < NumCols(); x++ )
  1209. for( int y = 0; y < NumRows(); y++ )
  1210. for( int c = 0; c < 3; c++ )
  1211. {
  1212. for( int i = 0; i < NDELTAS; i++ )
  1213. {
  1214. float norml = 1.1 * deltas[i]-> Pixel( x, y, 0, c );
  1215. // if (norml<0.0)
  1216. // norml=-pow(-norml,1.2);
  1217. // else
  1218. // norml=pow(norml,1.2);
  1219. deltas[i]-> Pixel( x, y, 0, c ) = norml;
  1220. }
  1221. }
  1222. // now, calculate modifiability
  1223. for( int x = 0; x < NumCols(); x++ )
  1224. for( int y = 0; y < NumRows(); y++ )
  1225. {
  1226. float modify = 0;
  1227. if (
  1228. ( x > 0 ) && ( x < NumCols() - 1 ) &&
  1229. ( y ) && ( y < NumRows() - 1 ) )
  1230. {
  1231. modify = 1;
  1232. Alpha( x, y, 0 ) = modify;
  1233. }
  1234. }
  1235. Poisson( deltas, 2200, 0 );
  1236. }
  1237. static inline float FLerp( float f1, float f2, float t )
  1238. {
  1239. return f1 + ( f2 - f1 ) * t;
  1240. }
  1241. void FloatBitMap_t::MakeTileable( void )
  1242. {
  1243. FloatBitMap_t rslta( this );
  1244. // now, need to make Difference map
  1245. FloatBitMap_t DiffMapX( this );
  1246. FloatBitMap_t DiffMapY( this );
  1247. // set each pixel=avg-pixel
  1248. FloatBitMap_t * cursrc =& rslta;
  1249. for( int x = 1; x < NumCols() - 1; x++ )
  1250. for( int y = 1; y < NumRows() - 1; y++ )
  1251. for( int c = 0; c < 3; c++ )
  1252. {
  1253. DiffMapX.Pixel( x, y, 0, c ) = Pixel( x, y, 0, c ) - Pixel( x + 1, y, 0, c );
  1254. DiffMapY.Pixel( x, y, 0, c ) = Pixel( x, y, 0, c ) - Pixel( x, y + 1, 0, c );
  1255. }
  1256. // initialize edge conditions
  1257. for( int x = 0; x < NumCols(); x++ )
  1258. {
  1259. for( int c = 0; c < 3; c++ )
  1260. {
  1261. float a = 0.5 * ( Pixel( x, NumRows() - 1, 0, c ) += Pixel( x, 0, 0, c ) );
  1262. rslta.Pixel( x, NumRows() - 1, 0, c ) = a;
  1263. rslta.Pixel( x, 0, 0, c ) = a;
  1264. }
  1265. }
  1266. for( int y = 0; y < NumRows(); y++ )
  1267. {
  1268. for( int c = 0; c < 3; c++ )
  1269. {
  1270. float a = 0.5 * ( Pixel( NumCols() - 1, y, 0, c ) + Pixel( 0, y, 0, c ) );
  1271. rslta.Pixel( NumCols() - 1, y, 0, c ) = a;
  1272. rslta.Pixel( 0, y, 0, c ) = a;
  1273. }
  1274. }
  1275. FloatBitMap_t rsltb( & rslta );
  1276. FloatBitMap_t * curdst =& rsltb;
  1277. // now, ready to iterate
  1278. for( int pass = 0; pass < 10; pass++ )
  1279. {
  1280. float error = 0.0;
  1281. for( int x = 1; x < NumCols() - 1; x++ )
  1282. for( int y = 1; y < NumRows() - 1; y++ )
  1283. for( int c = 0; c < 3; c++ )
  1284. {
  1285. float desiredx = DiffMapX.Pixel( x, y, 0, c ) + cursrc->Pixel( x + 1, y, 0, c );
  1286. float desiredy = DiffMapY.Pixel( x, y, 0, c ) + cursrc->Pixel( x, y + 1, 0, c );
  1287. float desired = 0.5 * ( desiredy + desiredx );
  1288. curdst->Pixel( x, y, 0, c ) = FLerp( cursrc->Pixel( x, y, 0, c ), desired, 0.5 );
  1289. error += SQ( desired - cursrc->Pixel( x, y, 0, c ) );
  1290. }
  1291. SWAP( cursrc, curdst );
  1292. }
  1293. // paste result
  1294. for( int x = 0; x < NumCols(); x++ )
  1295. for( int y = 0; y < NumRows(); y++ )
  1296. for( int c = 0; c < 3; c++ )
  1297. Pixel( x, y, 0, c ) = curdst->Pixel( x, y, 0, c );
  1298. }
  1299. void FloatBitMap_t::GetAlphaBounds( int & minx, int & miny, int & maxx, int & maxy )
  1300. {
  1301. for( minx = 0; minx < NumCols(); minx++ )
  1302. {
  1303. int y;
  1304. for( y = 0; y < NumRows(); y++ )
  1305. if ( Alpha( minx, y, 0 ) )
  1306. break;
  1307. if ( y != NumRows() )
  1308. break;
  1309. }
  1310. for( maxx = NumCols() - 1; maxx >= 0; maxx-- )
  1311. {
  1312. int y;
  1313. for( y = 0; y < NumRows(); y++ )
  1314. if ( Alpha( maxx, y, 0 ) )
  1315. break;
  1316. if ( y != NumRows() )
  1317. break;
  1318. }
  1319. for( miny = 0; minx < NumRows(); miny++ )
  1320. {
  1321. int x;
  1322. for( x = minx; x <= maxx; x++ )
  1323. if ( Alpha( x, miny, 0 ) )
  1324. break;
  1325. if ( x < maxx )
  1326. break;
  1327. }
  1328. for( maxy = NumRows() - 1; maxy >= 0; maxy-- )
  1329. {
  1330. int x;
  1331. for( x = minx; x <= maxx; x++ )
  1332. if ( Alpha( x, maxy, 0 ) )
  1333. break;
  1334. if ( x < maxx )
  1335. break;
  1336. }
  1337. }
  1338. void FloatBitMap_t::Poisson( FloatBitMap_t * deltas[4],
  1339. int n_iters,
  1340. uint32 flags // SPF_xxx
  1341. )
  1342. {
  1343. int minx, miny, maxx, maxy;
  1344. GetAlphaBounds( minx, miny, maxx, maxy );
  1345. minx = MAX( 1, minx );
  1346. miny = MAX( 1, miny );
  1347. maxx = MIN( NumCols() - 2, maxx );
  1348. maxy = MIN( NumRows() - 2, maxy );
  1349. if ( ( ( maxx - minx ) > 25 ) && ( maxy - miny ) > 25 )
  1350. {
  1351. // perform at low resolution
  1352. FloatBitMap_t * lowdeltas[NDELTAS];
  1353. for( int i = 0; i < NDELTAS; i++ )
  1354. {
  1355. lowdeltas[i] = new FloatBitMap_t;
  1356. deltas[i]->QuarterSize( lowdeltas[i] );
  1357. }
  1358. FloatBitMap_t * tmp = new FloatBitMap_t;
  1359. QuarterSize( tmp );
  1360. tmp->Poisson( lowdeltas, n_iters * 4, flags );
  1361. // now, propagate results from tmp to us
  1362. for( int x = 0; x < tmp->NumCols(); x++ )
  1363. for( int y = 0; y < tmp->NumRows(); y++ )
  1364. for( int xi = 0; xi < 2; xi++ )
  1365. for( int yi = 0; yi < 2; yi++ )
  1366. if ( Alpha( x * 2 + xi, y * 2 + yi, 0 ) )
  1367. {
  1368. for( int c = 0; c < 3; c++ )
  1369. Pixel( x * 2 + xi, y * 2 + yi, 0, c ) =
  1370. FLerp( Pixel( x * 2 + xi, y * 2 + yi, 0, c ), tmp->Pixel( x, y, 0, c ), Alpha( x * 2 + xi, y * 2 + yi, 0 ) );
  1371. }
  1372. char fname[80];
  1373. sprintf(fname,"sub%dx%d.tga",tmp->NumCols(),tmp->NumRows());
  1374. tmp->WriteTGAFile( fname );
  1375. sprintf(fname,"submrg%dx%d.tga",tmp->NumCols(),tmp->NumRows());
  1376. WriteTGAFile( fname );
  1377. delete tmp;
  1378. for( int i = 0; i < NDELTAS; i++ )
  1379. delete lowdeltas[i];
  1380. }
  1381. FloatBitMap_t work1( this );
  1382. FloatBitMap_t work2( this );
  1383. FloatBitMap_t * curdst =& work1;
  1384. FloatBitMap_t * cursrc =& work2;
  1385. // now, ready to iterate
  1386. while( n_iters-- )
  1387. {
  1388. float error = 0.0;
  1389. for( int x = minx; x <= maxx; x++ )
  1390. {
  1391. for( int y = miny; y <= maxy; y++ )
  1392. {
  1393. if ( Alpha( x, y, 0 ) )
  1394. {
  1395. for( int c = 0; c < 3; c++ )
  1396. {
  1397. float desired = 0.0;
  1398. for( int i = 0; i < NDELTAS; i++ )
  1399. desired += deltas[i]-> Pixel( x, y, 0, c ) + cursrc->Pixel( x + dx[i], y + dy[i], 0, c );
  1400. desired *= ( 1.0 / NDELTAS );
  1401. // desired=FLerp(Pixel(x,y,c),desired,Alpha(x,y));
  1402. curdst->Pixel( x, y, 0, c ) = FLerp( cursrc->Pixel( x, y, 0, c ), desired, 0.5 );
  1403. error += SQ( desired - cursrc->Pixel( x, y, 0, c ) );
  1404. }
  1405. }
  1406. SWAP( cursrc, curdst );
  1407. }
  1408. }
  1409. }
  1410. // paste result
  1411. for( int x = 0; x < NumCols(); x++ )
  1412. {
  1413. for( int y = 0; y < NumRows(); y++ )
  1414. {
  1415. for( int c = 0; c < 3; c++ )
  1416. {
  1417. Pixel( x, y, 0, c ) = curdst->Pixel( x, y, 0, c );
  1418. }
  1419. }
  1420. }
  1421. }