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.

522 lines
16 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "materialobjects/dmeimage.h"
  7. #include "datamodel/dmelementfactoryhelper.h"
  8. #include "bitmap/imageformat.h"
  9. //-----------------------------------------------------------------------------
  10. // Expose this class to the scene database
  11. //-----------------------------------------------------------------------------
  12. IMPLEMENT_ELEMENT_FACTORY( DmeImage, CDmeImage );
  13. //-----------------------------------------------------------------------------
  14. // Constructor, destructor
  15. //-----------------------------------------------------------------------------
  16. void CDmeImage::OnConstruction()
  17. {
  18. m_nWidth.Init( this, "width", FATTRIB_HIDDEN );
  19. m_nHeight.Init( this, "height", FATTRIB_HIDDEN );
  20. m_nDepth.Init( this, "depth", FATTRIB_HIDDEN );
  21. m_nFormat.Init( this, "format", FATTRIB_HIDDEN );
  22. m_flGamma.Init( this, "gamma", FATTRIB_HIDDEN );
  23. m_Bits.Init( this, "bits", FATTRIB_HIDDEN | FATTRIB_HAS_CALLBACK );
  24. m_Mode = DMEIMAGE_STORAGE_NONE;
  25. m_bInModification = false;
  26. m_bInFloatBitmapModification = false;
  27. m_bIgnoreChangedBitsAttribute = false;
  28. m_hModify = NULL;
  29. }
  30. void CDmeImage::OnDestruction()
  31. {
  32. Assert( !m_bInModification && !m_bInFloatBitmapModification );
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Used to make sure the attribute is well-behaved
  36. //-----------------------------------------------------------------------------
  37. void CDmeImage::OnAttributeChanged( CDmAttribute *pAttribute )
  38. {
  39. BaseClass::OnAttributeChanged( pAttribute );
  40. if ( pAttribute == m_Bits.GetAttribute() )
  41. {
  42. if ( !m_bIgnoreChangedBitsAttribute )
  43. {
  44. // If the attribute changed (undo), the attribute contains the bits;
  45. // discard the float bitmap state
  46. if ( m_Mode == DMEIMAGE_STORAGE_FLOAT_BITMAP )
  47. {
  48. SetFloatBitmapStorageMode( false, true );
  49. }
  50. }
  51. }
  52. }
  53. void CDmeImage::OnElementUnserialized()
  54. {
  55. BaseClass::OnElementUnserialized();
  56. // After reading, the attribute contains the bits; discard anything else
  57. if ( m_Mode != DMEIMAGE_STORAGE_ATTRIBUTE )
  58. {
  59. SetFloatBitmapStorageMode( false, true );
  60. }
  61. }
  62. void CDmeImage::OnElementSerialized()
  63. {
  64. BaseClass::OnElementSerialized();
  65. // Prior to serialization, make sure the bits attribute is holding the current bits
  66. if ( m_Mode == DMEIMAGE_STORAGE_FLOAT_BITMAP )
  67. {
  68. SetFloatBitmapStorageMode( false );
  69. }
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Initializes the buffer, doesn't allocate space
  73. //-----------------------------------------------------------------------------
  74. void CDmeImage::Init( int nWidth, int nHeight, int nDepth, ImageFormat fmt, float flGamma )
  75. {
  76. if ( IsUsingFloatBitmapStorageMode() )
  77. {
  78. m_ComputeBits.Shutdown();
  79. }
  80. m_Bits.Set( NULL, 0 );
  81. m_nWidth = nWidth;
  82. m_nHeight = nHeight;
  83. m_nDepth = nDepth;
  84. m_nFormat = fmt;
  85. m_flGamma = flGamma;
  86. m_Mode = DMEIMAGE_STORAGE_NONE;
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Image format
  90. //-----------------------------------------------------------------------------
  91. ImageFormat CDmeImage::Format() const
  92. {
  93. return (ImageFormat)( m_nFormat.Get() );
  94. }
  95. const char *CDmeImage::FormatName() const
  96. {
  97. return ImageLoader::GetName( Format() );
  98. }
  99. //-----------------------------------------------------------------------------
  100. // returns the size of one row
  101. //-----------------------------------------------------------------------------
  102. int CDmeImage::RowSizeInBytes( ) const
  103. {
  104. return ImageLoader::GetMemRequired( m_nWidth, 1, 1, Format(), false );
  105. }
  106. //-----------------------------------------------------------------------------
  107. // returns the size of one z slice
  108. //-----------------------------------------------------------------------------
  109. int CDmeImage::ZSliceSizeInBytes( ) const
  110. {
  111. return ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, Format(), false );
  112. }
  113. //-----------------------------------------------------------------------------
  114. // returns the total size of the image
  115. //-----------------------------------------------------------------------------
  116. int CDmeImage::SizeInBytes( ) const
  117. {
  118. return ImageLoader::GetMemRequired( m_nWidth, m_nHeight, m_nDepth, Format(), false );
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Converts the image into its requested storage mode
  122. //-----------------------------------------------------------------------------
  123. void CDmeImage::SetFloatBitmapStorageMode( bool bFloatBitmap, bool bDiscardContents )
  124. {
  125. Assert( !m_bInModification && !m_bInFloatBitmapModification );
  126. StorageMode_t nMode = ( bFloatBitmap ) ? DMEIMAGE_STORAGE_FLOAT_BITMAP : DMEIMAGE_STORAGE_ATTRIBUTE;
  127. if ( nMode == m_Mode )
  128. return;
  129. // Do this to avoid re-entrancy problems in BeginModification
  130. StorageMode_t nOldMode = m_Mode;
  131. m_Mode = nMode;
  132. switch( m_Mode )
  133. {
  134. case DMEIMAGE_STORAGE_NONE:
  135. break;
  136. case DMEIMAGE_STORAGE_ATTRIBUTE:
  137. if ( !bDiscardContents && ( nOldMode == DMEIMAGE_STORAGE_FLOAT_BITMAP ) )
  138. {
  139. m_nWidth = m_ComputeBits.NumCols();
  140. m_nHeight = m_ComputeBits.NumRows();
  141. m_nDepth = m_ComputeBits.NumSlices();
  142. CUtlBinaryBlock &buf = BeginModification();
  143. buf.SetLength( SizeInBytes() );
  144. m_ComputeBits.WriteToBuffer( buf.Get(), buf.Length(), Format(), Gamma() );
  145. EndModification();
  146. }
  147. else
  148. {
  149. // Question: If we're in float bitmap mode, but we discard contents,
  150. // should we copy back the dimensions?
  151. CUtlBinaryBlock &buf = BeginModification();
  152. buf.SetLength( SizeInBytes() );
  153. EndModification();
  154. }
  155. m_ComputeBits.Shutdown();
  156. break;
  157. case DMEIMAGE_STORAGE_FLOAT_BITMAP:
  158. const ImageFormatInfo_t &info = ImageLoader::ImageFormatInfo( Format() );
  159. int nMask = 0;
  160. if ( info.m_nNumRedBits > 0 ) nMask |= FBM_ATTR_RED_MASK;
  161. if ( info.m_nNumGreenBits > 0 ) nMask |= FBM_ATTR_GREEN_MASK;
  162. if ( info.m_nNumBlueBits > 0 ) nMask |= FBM_ATTR_BLUE_MASK;
  163. if ( info.m_nNumAlphaBits > 0 ) nMask |= FBM_ATTR_ALPHA_MASK;
  164. m_ComputeBits.Init( m_nWidth, m_nHeight, m_nDepth, nMask );
  165. if ( !bDiscardContents && ( nOldMode == DMEIMAGE_STORAGE_ATTRIBUTE ) )
  166. {
  167. m_ComputeBits.LoadFromBuffer( m_Bits.Get(), m_Bits.Length(), Format(), Gamma() );
  168. }
  169. break;
  170. }
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Copies the bits in whatever form they are currently in
  174. //-----------------------------------------------------------------------------
  175. void CDmeImage::CopyFrom( CDmeImage *pSrcImage, ImageFormat fmt )
  176. {
  177. if ( fmt == IMAGE_FORMAT_UNKNOWN )
  178. {
  179. fmt = pSrcImage->Format();
  180. }
  181. Init( pSrcImage->Width(), pSrcImage->Height(), pSrcImage->Depth(), fmt, pSrcImage->Gamma() );
  182. if ( !pSrcImage->HasImageData() )
  183. return;
  184. if ( pSrcImage->IsUsingFloatBitmapStorageMode() )
  185. {
  186. SetFloatBitmapStorageMode( true, true );
  187. m_ComputeBits.LoadFromFloatBitmap( pSrcImage->FloatBitmap() );
  188. }
  189. else
  190. {
  191. if ( pSrcImage->Format() == Format() )
  192. {
  193. SetImageBits( pSrcImage->ImageBits(), pSrcImage->SizeInBytes() );
  194. }
  195. else
  196. {
  197. int nMemory = ImageLoader::GetMemRequired( Width(), Height(), Depth(), 1, Format() );
  198. CUtlBinaryBlock &bits = BeginModification();
  199. bits.SetLength( nMemory );
  200. ImageLoader::ConvertImageFormat( (const uint8*)pSrcImage->ImageBits(), pSrcImage->Format(),
  201. (uint8*)bits.Get(), Format(), Width(), Height() * Depth() );
  202. EndModification();
  203. }
  204. }
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Color converts the image into the destination format.
  208. //-----------------------------------------------------------------------------
  209. void CDmeImage::ConvertFormat( ImageFormat fmt )
  210. {
  211. if ( fmt == m_nFormat )
  212. return;
  213. if ( ImageLoader::IsCompressed( Format() ) )
  214. {
  215. // Cannot convert from a compressed format
  216. Assert( 0 );
  217. return;
  218. }
  219. if ( ImageLoader::IsCompressed( fmt ) )
  220. {
  221. // Not supported for compressed textures
  222. Assert( 0 );
  223. return;
  224. }
  225. // NOTE: Not super fast, needs to copy the data here even if we use
  226. // the faster ImageLoader::ConvertImageFormat calls. And those
  227. // don't support volume textures. So, screw it. Doing an easier implementation.
  228. // This will convert it to 32323232F, and on return, it will convert
  229. // to the desired format.
  230. if ( m_Mode == DMEIMAGE_STORAGE_ATTRIBUTE )
  231. {
  232. SetFloatBitmapStorageMode( true );
  233. }
  234. m_nFormat = fmt;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Sets the color of every pixel
  238. //-----------------------------------------------------------------------------
  239. void CDmeImage::Clear( float r, float g, float b, float a )
  240. {
  241. SetFloatBitmapStorageMode( true, true );
  242. m_ComputeBits.Clear( r, g, b, a );
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Compresses an image into this image
  246. //-----------------------------------------------------------------------------
  247. void CDmeImage::CompressImage( CDmeImage *pSrcImage, ImageFormat fmt )
  248. {
  249. if ( ImageLoader::IsCompressed( pSrcImage->Format() ) )
  250. {
  251. // Cannot convert from a compressed format
  252. Assert( 0 );
  253. return;
  254. }
  255. // Must be a compressed format
  256. if ( !ImageLoader::IsCompressed( fmt ) )
  257. {
  258. Assert( 0 );
  259. return;
  260. }
  261. Init( pSrcImage->Width(), pSrcImage->Height(), pSrcImage->Depth(), fmt, pSrcImage->Gamma() );
  262. // We can only convert from a few well-known formats
  263. pSrcImage->ConvertFormat( IMAGE_FORMAT_RGBA8888 );
  264. int nSrcFaceStride = pSrcImage->ZSliceSizeInBytes();
  265. int nDstFaceStride = ZSliceSizeInBytes();
  266. CUtlBinaryBlock &dstBlock = BeginModification();
  267. dstBlock.SetLength( SizeInBytes() );
  268. const uint8* pSrcData = reinterpret_cast< const uint8* >( pSrcImage->ImageBits() );
  269. uint8* pDstData = reinterpret_cast< uint8* >( dstBlock.Get() );
  270. for ( int z = 0; z < Depth(); ++z, pSrcData += nSrcFaceStride, pDstData += nDstFaceStride )
  271. {
  272. ImageLoader::ConvertImageFormat( pSrcData, pSrcImage->Format(),
  273. pDstData, fmt, pSrcImage->Width(), pSrcImage->Height() );
  274. }
  275. EndModification();
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Reinterprets the image as a new color format; no work is done
  279. //-----------------------------------------------------------------------------
  280. void CDmeImage::ReinterpetFormat( ImageFormat fmt )
  281. {
  282. if ( ImageLoader::SizeInBytes( fmt ) != ImageLoader::SizeInBytes( Format() ) )
  283. {
  284. // Src + dst format must be the same size for this to work!
  285. Assert( 0 );
  286. return;
  287. }
  288. m_nFormat = fmt;
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Copies bits into the image bits buffer
  292. //-----------------------------------------------------------------------------
  293. void CDmeImage::SetImageBits( const void *pBits, int nSize )
  294. {
  295. SetFloatBitmapStorageMode( false, true );
  296. m_Bits.Set( pBits, nSize );
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Used for bit modification
  300. //-----------------------------------------------------------------------------
  301. CUtlBinaryBlock &CDmeImage::BeginModification( )
  302. {
  303. SetFloatBitmapStorageMode( false );
  304. Assert( !m_bInModification && !m_bInFloatBitmapModification );
  305. m_bInModification = true;
  306. return m_Bits.GetAttribute()->BeginModifyValueInPlace< CUtlBinaryBlock >( &m_hModify );
  307. }
  308. void CDmeImage::EndModification( )
  309. {
  310. Assert( m_bInModification && !m_bInFloatBitmapModification );
  311. m_bInModification = false;
  312. m_bIgnoreChangedBitsAttribute = true;
  313. m_Bits.GetAttribute()->EndModifyValueInPlace< CUtlBinaryBlock >( m_hModify );
  314. m_bIgnoreChangedBitsAttribute = false;
  315. m_hModify = NULL;
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Used for float bitmap modification
  319. //-----------------------------------------------------------------------------
  320. FloatBitMap_t &CDmeImage::BeginFloatBitmapModification( )
  321. {
  322. SetFloatBitmapStorageMode( true );
  323. Assert( !m_bInModification && !m_bInFloatBitmapModification );
  324. m_bInFloatBitmapModification = true;
  325. return m_ComputeBits;
  326. }
  327. void CDmeImage::EndFloatBitmapModification( )
  328. {
  329. Assert( m_bInFloatBitmapModification && !m_bInModification );
  330. m_bInFloatBitmapModification = false;
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Image data
  334. //-----------------------------------------------------------------------------
  335. const FloatBitMap_t *CDmeImage::FloatBitmap()
  336. {
  337. SetFloatBitmapStorageMode( true );
  338. return &m_ComputeBits;
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Creates an image 1/4 size of the source using a box filter
  342. //-----------------------------------------------------------------------------
  343. void CDmeImage::QuarterSize( CDmeImage *pSrcImage )
  344. {
  345. SetFloatBitmapStorageMode( true, true );
  346. pSrcImage->SetFloatBitmapStorageMode( true );
  347. pSrcImage->m_ComputeBits.QuarterSize( &m_ComputeBits );
  348. m_nFormat = pSrcImage->Format();
  349. m_flGamma = pSrcImage->Gamma();
  350. }
  351. //-----------------------------------------------------------------------------
  352. // Downsample using nice filter (NOTE: Dest bitmap needs to have been initialized w/ final size)
  353. //-----------------------------------------------------------------------------
  354. void CDmeImage::DownsampleNiceFiltered( const DownsampleInfo_t& info, CDmeImage *pSrcImage )
  355. {
  356. SetFloatBitmapStorageMode( true, true );
  357. pSrcImage->SetFloatBitmapStorageMode( true );
  358. pSrcImage->m_ComputeBits.DownsampleNiceFiltered( info, &m_ComputeBits );
  359. m_nFormat = pSrcImage->Format();
  360. m_flGamma = pSrcImage->Gamma();
  361. }
  362. //-----------------------------------------------------------------------------
  363. // Expose this class to the scene database
  364. //-----------------------------------------------------------------------------
  365. IMPLEMENT_ELEMENT_FACTORY( DmeImageArray, CDmeImageArray );
  366. //-----------------------------------------------------------------------------
  367. // Constructor, destructor
  368. //-----------------------------------------------------------------------------
  369. void CDmeImageArray::OnConstruction()
  370. {
  371. m_Images.Init( this, "images" );
  372. }
  373. void CDmeImageArray::OnDestruction()
  374. {
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Image format
  378. //-----------------------------------------------------------------------------
  379. int CDmeImageArray::ImageCount() const
  380. {
  381. return m_Images.Count();
  382. }
  383. CDmeImage *CDmeImageArray::GetImage( int nIndex ) const
  384. {
  385. return m_Images[nIndex];
  386. }
  387. bool CDmeImageArray::IsConsistent( int nWidth, int nHeight, int nDepth, ImageFormat fmt ) const
  388. {
  389. if ( ImageCount() == 0 )
  390. return true;
  391. CDmeImage *pFirstImage = m_Images[0];
  392. return ( nWidth == pFirstImage->Width() && nHeight == pFirstImage->Height() &&
  393. fmt == pFirstImage->Format() && nDepth == pFirstImage->Depth() );
  394. }
  395. void CDmeImageArray::AddImage( CDmeImage *pImage )
  396. {
  397. if ( !IsConsistent( pImage->Width(), pImage->Height(), pImage->Depth(), pImage->Format() ) )
  398. {
  399. Warning( "Attempted to add different size/format images to the image array!\n" );
  400. return;
  401. }
  402. m_Images.AddToTail( pImage );
  403. }
  404. CDmeImage *CDmeImageArray::AddImage( )
  405. {
  406. CDmeImage *pImage = CreateElement< CDmeImage >( "image", GetFileId() );
  407. if ( ImageCount() > 0 )
  408. {
  409. CDmeImage *pFirstImage = m_Images[0];
  410. pImage->Init( pFirstImage->Width(), pFirstImage->Height(),
  411. pFirstImage->Depth(), pFirstImage->Format(), pFirstImage->Gamma() );
  412. }
  413. AddImage( pImage );
  414. return pImage;
  415. }
  416. // Gets dimensions
  417. int CDmeImageArray::Width() const
  418. {
  419. return ( ImageCount() > 0 ) ? m_Images[0]->Width() : -1;
  420. }
  421. int CDmeImageArray::Height() const
  422. {
  423. return ( ImageCount() > 0 ) ? m_Images[0]->Height() : -1;
  424. }
  425. int CDmeImageArray::Depth() const
  426. {
  427. return ( ImageCount() > 0 ) ? m_Images[0]->Depth() : -1;
  428. }
  429. ImageFormat CDmeImageArray::Format() const
  430. {
  431. return ( ImageCount() > 0 ) ? m_Images[0]->Format() : IMAGE_FORMAT_UNKNOWN;
  432. }