Team Fortress 2 Source Code as on 22/4/2020
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.

461 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "bitmap/bitmap.h"
  7. #include "dbg.h"
  8. // Should be last include
  9. #include "tier0/memdbgon.h"
  10. bool Bitmap_t::IsValid() const
  11. {
  12. if ( m_nWidth <= 0 || m_nHeight <= 0 || m_pBits == NULL )
  13. {
  14. Assert( m_nWidth == 0 );
  15. Assert( m_nHeight == 0 );
  16. Assert( m_pBits == NULL );
  17. return false;
  18. }
  19. return true;
  20. }
  21. void Bitmap_t::Clear()
  22. {
  23. if ( m_pBits && m_bOwnsBuffer )
  24. {
  25. free( m_pBits );
  26. }
  27. Reset();
  28. }
  29. void Bitmap_t::Init( int xs, int ys, ImageFormat imageFormat, int nStride )
  30. {
  31. // Check for bogus allocation sizes
  32. if (xs <= 0 || ys <= 0 )
  33. {
  34. Assert( xs == 0 );
  35. Assert( ys == 0 );
  36. Clear();
  37. return;
  38. }
  39. int nPixSize = ImageLoader::SizeInBytes( imageFormat );
  40. // Auto detect stride
  41. if ( nStride == 0 )
  42. {
  43. nStride = nPixSize * xs;
  44. }
  45. // Check for NOP
  46. if (
  47. m_pBits
  48. && m_bOwnsBuffer
  49. && m_nWidth == xs
  50. && m_nHeight == ys
  51. && nStride == m_nStride
  52. && nPixSize == m_nPixelSize )
  53. {
  54. // We're already got a buffer of the right size.
  55. // The only thing that might be wrong is the pixel format.
  56. m_ImageFormat = imageFormat;
  57. return;
  58. }
  59. // Free up anything already allocated
  60. Clear();
  61. // Remember dimensions and pixel format
  62. m_nWidth = xs;
  63. m_nHeight = ys;
  64. m_ImageFormat = imageFormat;
  65. m_nPixelSize = nPixSize;
  66. m_nStride = nStride;
  67. // Allocate buffer. Because this is a PC game,
  68. // failure is impossible....right?
  69. m_pBits = (byte *)malloc( ys * m_nStride );
  70. // Assume ownership
  71. m_bOwnsBuffer = true;
  72. }
  73. void Bitmap_t::SetBuffer( int nWidth, int nHeight, ImageFormat imageFormat, unsigned char *pBits, bool bAssumeOwnership, int nStride )
  74. {
  75. Assert( pBits );
  76. Assert( nWidth > 0 );
  77. Assert( nHeight > 0 );
  78. // Free up anything already allocated
  79. Clear();
  80. // Remember dimensions and pixel format
  81. m_nWidth = nWidth;
  82. m_nHeight = nHeight;
  83. m_ImageFormat = imageFormat;
  84. m_nPixelSize = ImageLoader::SizeInBytes( imageFormat );
  85. if ( nStride == 0 )
  86. {
  87. m_nStride = m_nPixelSize * nWidth;
  88. }
  89. else
  90. {
  91. m_nStride = nStride;
  92. }
  93. // Set our buffer pointer
  94. m_pBits = pBits;
  95. // Assume ownership of the buffer, if requested
  96. m_bOwnsBuffer = bAssumeOwnership;
  97. // We should be good to go
  98. Assert( IsValid() );
  99. }
  100. Color Bitmap_t::GetColor( int x, int y ) const
  101. {
  102. Assert( x >= 0 && x < m_nWidth );
  103. Assert( y >= 0 && y < m_nHeight );
  104. Assert( m_pBits );
  105. // Get pointer to pixel data
  106. byte *ptr = m_pBits + (y*m_nStride) + x* m_nPixelSize;
  107. // Check supported image formats
  108. switch ( m_ImageFormat )
  109. {
  110. case IMAGE_FORMAT_RGBA8888:
  111. return Color( ptr[0], ptr[1], ptr[2], ptr[3] );
  112. case IMAGE_FORMAT_ABGR8888:
  113. return Color( ptr[3], ptr[2], ptr[1], ptr[0] );
  114. default:
  115. Assert( !"Unsupport image format!");
  116. return Color( 255,0,255,255 );
  117. }
  118. }
  119. void Bitmap_t::SetColor( int x, int y, Color c )
  120. {
  121. Assert( x >= 0 && x < m_nWidth );
  122. Assert( y >= 0 && y < m_nHeight );
  123. Assert( m_pBits );
  124. // Get pointer to pixel data
  125. byte *ptr = m_pBits + (y*m_nStride) + x* m_nPixelSize;
  126. // Check supported image formats
  127. switch ( m_ImageFormat )
  128. {
  129. case IMAGE_FORMAT_RGBA8888:
  130. ptr[0] = c.r();
  131. ptr[1] = c.g();
  132. ptr[2] = c.b();
  133. ptr[3] = c.a();
  134. break;
  135. case IMAGE_FORMAT_ABGR8888:
  136. ptr[0] = c.a();
  137. ptr[1] = c.b();
  138. ptr[2] = c.g();
  139. ptr[3] = c.r();
  140. break;
  141. default:
  142. Assert( !"Unsupport image format!");
  143. break;
  144. }
  145. }
  146. //bool LoadVTF( const char *pszFilename )
  147. //{
  148. //
  149. // // Load the raw file data
  150. // CUtlBuffer fileData;
  151. // if ( !filesystem->ReadFile( pszFilename, "game", fileData ) )
  152. // {
  153. // Warning( "Failed to load %s\n", pszFilename);
  154. // return false;
  155. // }
  156. //
  157. // return LoadVTFFromBuffer( fileData, pszFilename );
  158. //}
  159. //
  160. //bool LoadVTFFromBuffer( CUtlBuffer fileData, const char *pszDebugName = "buffer" )
  161. //{
  162. //
  163. // // Parse it into VTF object
  164. // IVTFTexture *pVTFTexture( CreateVTFTexture() );
  165. // if ( !pVTFTexture->Unserialize( fileData ) )
  166. // {
  167. // DestroyVTFTexture( pVTFTexture );
  168. // Warning( "Failed to deserialize VTF %s\n", pszDebugName);
  169. // return false;
  170. // }
  171. //
  172. // // We are re-reading our own files, so they should be 8888's
  173. // if ( pVTFTexture->Format() != IMAGE_FORMAT_RGBA8888 )
  174. // {
  175. // DestroyVTFTexture( pVTFTexture );
  176. // Warning( "%s isn't RGBA8888\n", pszDebugName);
  177. // return false;
  178. // }
  179. //
  180. // // Copy the image data
  181. // Allocate( pVTFTexture->Width(), pVTFTexture->Height() );
  182. // for ( int y = 0 ; y < m_nHeight ; ++y )
  183. // {
  184. // memcpy( PixPtr(0, y), pVTFTexture->ImageData(0, 0, 0, 0, y), m_nWidth*4 );
  185. // }
  186. //
  187. // // Clean up
  188. // DestroyVTFTexture( pVTFTexture );
  189. // return true;
  190. //}
  191. //
  192. //bool SaveVTF( CUtlBuffer &outBuffer )
  193. //{
  194. // // Create the VTF to write into
  195. // IVTFTexture *pVTFTexture( CreateVTFTexture() );
  196. // const int nFlags = TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_SRGB;
  197. // if ( !pVTFTexture->Init( m_nWidth, m_nHeight, 1, IMAGE_FORMAT_RGBA8888, nFlags, 1, 1 ) )
  198. // {
  199. // DestroyVTFTexture( pVTFTexture );
  200. // return false;
  201. // }
  202. //
  203. // // write the rgba image to the vtf texture using the pixel writer
  204. // CPixelWriter pixelWriter;
  205. // pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData(), pVTFTexture->RowSizeInBytes( 0 ) );
  206. //
  207. // for (int y = 0; y < m_nHeight; ++y)
  208. // {
  209. // pixelWriter.Seek( 0, y );
  210. // for (int x = 0; x < m_nWidth; ++x)
  211. // {
  212. // Color c = GetPix( x, y );
  213. // pixelWriter.WritePixel( c.r(), c.g(), c.b(), c.a() );
  214. // }
  215. // }
  216. //
  217. // // Serialize to the buffer
  218. // if ( !pVTFTexture->Serialize( outBuffer ) )
  219. // {
  220. // DestroyVTFTexture( pVTFTexture );
  221. // return false;
  222. // }
  223. // DestroyVTFTexture( pVTFTexture );
  224. // return true;
  225. //}
  226. //void Resize( int nNewSizeX, int nNewSizeY, const Image *pImgSrc = NULL )
  227. //{
  228. // if ( pImgSrc == NULL )
  229. // {
  230. // pImgSrc = this;
  231. // }
  232. //
  233. // if ( nNewSizeX == m_nWidth && nNewSizeY == m_nHeight && pImgSrc == this )
  234. // {
  235. // return;
  236. // }
  237. //
  238. // byte *pNewData = (byte *)malloc( nNewSizeX * nNewSizeY * 4 );
  239. // ImgUtl_StretchRGBAImage( pImgSrc->m_pBits, pImgSrc->m_nWidth, pImgSrc->m_nHeight, pNewData, nNewSizeX, nNewSizeY );
  240. // Clear();
  241. // m_pBits = pNewData;
  242. // m_nWidth = nNewSizeX;
  243. // m_nHeight = nNewSizeY;
  244. //}
  245. //
  246. //void Crop( int x0, int y0, int nNewSizeX, int nNewSizeY, const Image *pImgSrc )
  247. //{
  248. // if ( pImgSrc == NULL )
  249. // {
  250. // pImgSrc = this;
  251. // }
  252. //
  253. // if ( nNewSizeX == m_nWidth && nNewSizeY == m_nHeight && pImgSrc == this )
  254. // {
  255. // return;
  256. // }
  257. //
  258. //
  259. // Assert( x0 >= 0 );
  260. // Assert( y0 >= 0 );
  261. // Assert( x0 + nNewSizeX <= pImgSrc->m_nWidth );
  262. // Assert( y0 + nNewSizeY <= pImgSrc->m_nHeight );
  263. //
  264. // // Allocate new buffer
  265. // int nRowSize = nNewSizeX * 4;
  266. // byte *pNewData = (byte *)malloc( nNewSizeY * nRowSize );
  267. //
  268. // // Copy data, one row at a time
  269. // for ( int y = 0 ; y < nNewSizeY ; ++y )
  270. // {
  271. // memcpy( pNewData + y*nRowSize, pImgSrc->PixPtr(x0, y0+y), nRowSize );
  272. // }
  273. //
  274. // // Replace current buffer with the new one
  275. // Clear();
  276. // m_pBits = pNewData;
  277. // m_nWidth = nNewSizeX;
  278. // m_nHeight = nNewSizeY;
  279. //}
  280. void Bitmap_t::MakeLogicalCopyOf( Bitmap_t &src, bool bTransferBufferOwnership )
  281. {
  282. // What does it mean to make a logical copy of an
  283. // invalid bitmap? I'll tell you what it means: you have a bug.
  284. Assert( src.IsValid() );
  285. // Free up anything we already own
  286. Clear();
  287. // Copy all of the member variables so we are
  288. // a logical copy of the source bitmap
  289. m_nWidth = src.m_nWidth;
  290. m_nHeight = src.m_nHeight;
  291. m_nPixelSize = src.m_nPixelSize;
  292. m_nStride = src.m_nStride;
  293. m_ImageFormat = src.m_ImageFormat;
  294. m_pBits = src.m_pBits;
  295. Assert( !m_bOwnsBuffer );
  296. // Check for assuming ownership of the buffer
  297. if ( bTransferBufferOwnership )
  298. {
  299. if ( src.m_bOwnsBuffer )
  300. {
  301. m_bOwnsBuffer = true;
  302. src.m_bOwnsBuffer = false;
  303. }
  304. else
  305. {
  306. // They don't own the buffer? Then who does?
  307. // Maybe nobody, and it would safe to assume
  308. // ownership. But more than likely, this is a
  309. // bug.
  310. Assert( src.m_bOwnsBuffer );
  311. // And a leak is better than a double-free.
  312. // Don't assume ownership of the buffer.
  313. }
  314. }
  315. }
  316. void Bitmap_t::Crop( int x0, int y0, int nWidth, int nHeight, const Bitmap_t *pImgSource )
  317. {
  318. // Check for cropping in place, then save off our data to a temp
  319. Bitmap_t temp;
  320. if ( pImgSource == this || !pImgSource )
  321. {
  322. temp.MakeLogicalCopyOf( *this, m_bOwnsBuffer );
  323. pImgSource = &temp;
  324. }
  325. // No source image?
  326. if ( !pImgSource->IsValid() )
  327. {
  328. Assert( pImgSource->IsValid() );
  329. return;
  330. }
  331. // Sanity check crop rectangle
  332. Assert( x0 >= 0 );
  333. Assert( y0 >= 0 );
  334. Assert( x0 + nWidth <= pImgSource->Width() );
  335. Assert( y0 + nHeight <= pImgSource->Height() );
  336. // Allocate buffer
  337. Init( nWidth, nHeight, pImgSource->Format() );
  338. // Something wrong?
  339. if ( !IsValid() )
  340. {
  341. Assert( IsValid() );
  342. return;
  343. }
  344. // Copy the data a row at a time
  345. int nRowSize = m_nWidth * m_nPixelSize;
  346. for ( int y = 0 ; y < m_nHeight ; ++y )
  347. {
  348. memcpy( GetPixel(0,y), pImgSource->GetPixel( x0, y + y0 ), nRowSize );
  349. }
  350. }
  351. void Bitmap_t::SetPixelData( const Bitmap_t &src, int nSrcX1, int nSrcY1, int nCopySizeX, int nCopySizeY, int nDestX1, int nDestY1 )
  352. {
  353. // Safety
  354. if ( !src.IsValid() )
  355. {
  356. Assert( src.IsValid() );
  357. return;
  358. }
  359. if ( !IsValid() )
  360. {
  361. Assert( IsValid() );
  362. return;
  363. }
  364. // You need to specify a valid source rectangle, we cannot clip that for you
  365. if ( nSrcX1 < 0 || nSrcY1 < 0 || nSrcX1 + nCopySizeX > src.Width() || nSrcY1 + nCopySizeY > src.Height() )
  366. {
  367. Assert( nSrcX1 >= 0 );
  368. Assert( nSrcY1 >= 0 );
  369. Assert( nSrcX1 + nCopySizeX <= src.Width() );
  370. Assert( nSrcY1 + nCopySizeY <= src.Height() );
  371. return;
  372. }
  373. // But we can clip the rectangle if it extends outside the destination image in a perfectly
  374. // reasonable way
  375. if ( nDestX1 < 0 )
  376. {
  377. nCopySizeX += nDestX1;
  378. nDestX1 = 0;
  379. }
  380. if ( nDestX1 + nCopySizeX > Width() )
  381. {
  382. nCopySizeX = Width() - nDestX1;
  383. }
  384. if ( nDestY1 < 0 )
  385. {
  386. nCopySizeY += nDestY1;
  387. nDestY1 = 0;
  388. }
  389. if ( nDestY1 + nCopySizeY > Height() )
  390. {
  391. nCopySizeY = Height() - nDestY1;
  392. }
  393. if ( nCopySizeX <= 0 || nCopySizeY <= 0 )
  394. {
  395. return;
  396. }
  397. // Copy the pixel data
  398. for ( int y = 0 ; y < nCopySizeY ; ++y )
  399. {
  400. // Wow, this could be a lot faster in the common case
  401. // that the pixe formats are the same. But...this code
  402. // is simple and works, and is NOT the root of all evil.
  403. for ( int x = 0 ; x < nCopySizeX ; ++x )
  404. {
  405. Color c = src.GetColor( nSrcX1 + x, nSrcY1 + y );
  406. SetColor( nDestX1 + x, nDestY1 + y, c );
  407. }
  408. }
  409. }
  410. void Bitmap_t::SetPixelData( const Bitmap_t &src, int nDestX1, int nDestY1 )
  411. {
  412. SetPixelData( src, 0, 0, src.Width(), src.Height(), nDestX1, nDestY1 );
  413. }