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.

937 lines
27 KiB

  1. //===== Copyright � 2005-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: build a sheet data file and a large image out of multiple images
  4. //
  5. //===========================================================================//
  6. #include "materialobjects/dmeamalgtexture.h"
  7. #include "bitmap/floatbitmap.h"
  8. #include "tier2/fileutils.h"
  9. #include "datamodel/dmelementfactoryhelper.h"
  10. #include "materialobjects/dmesheetsequence.h"
  11. #include "resourcefile/schema/sheet.g.h"
  12. #include "resourcefile/resourcestream.h"
  13. #include "materialobjects/dmeimage.h"
  14. #include "bitmap/psheet.h"
  15. #include "tier0/dbg.h"
  16. //-----------------------------------------------------------------------------
  17. // Helper functions
  18. //-----------------------------------------------------------------------------
  19. static int GetChannelIndexFromChar( char c )
  20. {
  21. // r->0 b->1 g->2 a->3 else -1
  22. static char s_ChannelIDs[] = "rgba";
  23. char const *pChanChar = strchr( s_ChannelIDs, c );
  24. if ( ! pChanChar )
  25. {
  26. Warning( " bad channel name '%c'\n", c );
  27. return -1;
  28. }
  29. else
  30. {
  31. return pChanChar - s_ChannelIDs;
  32. }
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Clear the contents of the channel
  36. //-----------------------------------------------------------------------------
  37. static void ZeroChannel( FloatBitMap_t *newBitmap, FloatBitMap_t *pBitmap, int nDestChannel )
  38. {
  39. for ( int y = 0; y < newBitmap->NumRows(); y++ )
  40. {
  41. for ( int x = 0; x < newBitmap->NumCols(); x++ )
  42. {
  43. pBitmap->Pixel( x, y, 0, nDestChannel ) = 0;
  44. }
  45. }
  46. }
  47. //-----------------------------------------------------------------------------
  48. //
  49. //-----------------------------------------------------------------------------
  50. static void CopyChannel( FloatBitMap_t *newBitmap, FloatBitMap_t *pBitmap, int nSrcChannel, int nDestChannel )
  51. {
  52. for ( int y = 0; y < newBitmap->NumRows(); y++ )
  53. {
  54. for ( int x = 0; x < newBitmap->NumCols(); x++ )
  55. {
  56. pBitmap->Pixel( x, y, 0, nDestChannel ) = newBitmap->Pixel( x, y, 0, nSrcChannel );
  57. }
  58. }
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Get a full path to fname that is under mod/content/materialsrc
  62. // This is where all tgas live.
  63. //-----------------------------------------------------------------------------
  64. void GetFullPathUsingMaterialsrcContent( const char * fname, char *pFullTGAFileNameDest, int fullPathBufferSize )
  65. {
  66. char localTexturePath[MAX_PATH];
  67. Q_snprintf( localTexturePath, sizeof(localTexturePath), "materialsrc\\%s", fname );
  68. const char *result = g_pFullFileSystem->RelativePathToFullPath( localTexturePath, "CONTENT", pFullTGAFileNameDest, fullPathBufferSize );
  69. if ( result == NULL )
  70. {
  71. Warning( "CDataModel: Unable to generate full path for file %s\n", fname );
  72. pFullTGAFileNameDest = NULL;
  73. }
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Get a full path to fname that is under the current directory.
  77. // mksheet is meant to be run from a dir that contains all the tga files
  78. // referred to by the .mks file. This fxn lets it find the local files.
  79. //-----------------------------------------------------------------------------
  80. void GetFullPathUsingCurrentDir( const char * fname, char *pFullTGAFileNameDest, int fullPathBufferSize )
  81. {
  82. char pDir[MAX_PATH];
  83. if ( g_pFullFileSystem->GetCurrentDirectory( pDir, sizeof(pDir) ) )
  84. {
  85. CUtlString fullPathName = pDir;
  86. fullPathName += "\\";
  87. fullPathName += fname;
  88. Q_strncpy( pFullTGAFileNameDest, fullPathName.Get(), fullPathBufferSize );
  89. }
  90. else
  91. {
  92. Warning( "CDataModel: Unable to generate full path for file %s\n", fname );
  93. pFullTGAFileNameDest = NULL;
  94. }
  95. }
  96. //-----------------------------------------------------------------------------
  97. //
  98. //-----------------------------------------------------------------------------
  99. static FloatBitMap_t *CreateFloatBitmap( const char *pFilename, bool bUseCurrentDir = false )
  100. {
  101. if ( strchr( pFilename, ',' ) == NULL )
  102. {
  103. char fullTGAFileName[ MAX_PATH ];
  104. if ( Q_IsAbsolutePath( pFilename ) )
  105. {
  106. Q_strncpy( fullTGAFileName, pFilename, sizeof( fullTGAFileName ) );
  107. }
  108. else
  109. {
  110. if ( bUseCurrentDir )
  111. {
  112. GetFullPathUsingCurrentDir( pFilename, fullTGAFileName, sizeof(fullTGAFileName) );
  113. }
  114. else
  115. {
  116. GetFullPathUsingMaterialsrcContent( pFilename, fullTGAFileName, sizeof(fullTGAFileName) );
  117. }
  118. }
  119. if ( fullTGAFileName == NULL )
  120. {
  121. Warning( "CDataModel: Unable to generate full path for file %s\n", pFilename );
  122. }
  123. return new FloatBitMap_t( fullTGAFileName );
  124. }
  125. // Warning this is Untested not in use currently.
  126. // parse extended specifications
  127. CUtlVector<char *> Images;
  128. V_SplitString( pFilename, ",", Images );
  129. FloatBitMap_t *pBitmap = NULL;
  130. // now, process bitmaps, performing copy operations specified by {} syntax
  131. for( int i = 0; i < Images.Count(); i++ )
  132. {
  133. char fnamebuf[MAX_PATH];
  134. strcpy( fnamebuf, Images[i] );
  135. char * pBrace = strchr( fnamebuf, '{' );
  136. if ( pBrace )
  137. {
  138. *pBrace = 0; // null it
  139. pBrace++; // point at control specifier
  140. char *pEndBrace = strchr( pBrace, '}' );
  141. if ( ! pEndBrace )
  142. {
  143. Msg( "bad extended bitmap synax (no close brace) - %s \n", Images[i] );
  144. }
  145. }
  146. FloatBitMap_t newBitmap( fnamebuf );
  147. if ( !pBitmap )
  148. {
  149. // first image sets size
  150. pBitmap = new FloatBitMap_t( &newBitmap );
  151. }
  152. // now, process operation specifiers of the form "{chan=chan}" or "{chan=0}"
  153. if ( pBrace && ( pBrace[1] == '=' ) )
  154. {
  155. int nDstChan = GetChannelIndexFromChar( pBrace[0] );
  156. if ( nDstChan != -1 )
  157. {
  158. if ( pBrace[2] == '0' )
  159. {
  160. // zero the channel
  161. ZeroChannel( &newBitmap, pBitmap, nDstChan );
  162. }
  163. else
  164. {
  165. int nSrcChan = GetChannelIndexFromChar( pBrace[2] );
  166. if ( nSrcChan != -1 )
  167. {
  168. // perform the channel copy
  169. CopyChannel( &newBitmap, pBitmap, nSrcChan, nDstChan );
  170. }
  171. }
  172. }
  173. }
  174. }
  175. return pBitmap;
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Expose this class to the scene database
  179. //-----------------------------------------------------------------------------
  180. IMPLEMENT_ELEMENT_FACTORY( DmeAmalgamatedTexture, CDmeAmalgamatedTexture );
  181. void CDmeAmalgamatedTexture::OnConstruction()
  182. {
  183. m_ImageList.Init( this, "images" );
  184. m_ePackingMode.InitAndSet( this, "packmode", PCKM_FLAT );
  185. m_Sequences.Init( this, "sequences" );
  186. m_nWidth.Init( this, "width" );
  187. m_nHeight.Init( this, "height" );
  188. m_pPackedImage.Init( this, "packedImage" );
  189. m_SequenceCount = 0;
  190. }
  191. void CDmeAmalgamatedTexture::OnDestruction()
  192. {
  193. }
  194. //-----------------------------------------------------------------------------
  195. //
  196. //-----------------------------------------------------------------------------
  197. void CDmeAmalgamatedTexture::Init( const char *pShtFileName, bool bUseCurrentDir )
  198. {
  199. CDisableUndoScopeGuard sg;
  200. m_pCurSequence = NULL;
  201. // Load up the image bitmaps.
  202. char pFullDir[MAX_PATH];
  203. Q_strncpy( pFullDir, pShtFileName, sizeof(pFullDir) );
  204. Q_StripFilename( pFullDir );
  205. char pFullPath[MAX_PATH];
  206. for( int i = 0; i < m_ImageList.Count(); i++ )
  207. {
  208. // FIXME: Ugh!
  209. const char *pImageName = m_ImageList[i]->GetName();
  210. if ( bUseCurrentDir && Q_IsAbsolutePath( pShtFileName ) )
  211. {
  212. Q_ComposeFileName( pFullDir, pImageName, pFullPath, sizeof(pFullPath) );
  213. pImageName = pFullPath;
  214. }
  215. m_ImageList[i]->m_pImage = CreateFloatBitmap( pImageName, bUseCurrentDir );
  216. }
  217. m_SequenceCount = 0;
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Whether the frames loop or not
  221. //-----------------------------------------------------------------------------
  222. void CDmeAmalgamatedTexture::SetCurrentSequenceClamp( bool bState )
  223. {
  224. if ( m_pCurSequence )
  225. {
  226. m_pCurSequence->m_Clamp = bState;
  227. }
  228. }
  229. //-----------------------------------------------------------------------------
  230. //
  231. //-----------------------------------------------------------------------------
  232. int CDmeAmalgamatedTexture::GetPackingMode()
  233. {
  234. return m_ePackingMode;
  235. }
  236. //-----------------------------------------------------------------------------
  237. //
  238. //-----------------------------------------------------------------------------
  239. void CDmeAmalgamatedTexture::SetPackingMode( int eMode )
  240. {
  241. // Assign the packing mode read in to member var.
  242. if ( !m_Sequences.Count() )
  243. {
  244. m_ePackingMode = eMode;
  245. }
  246. else if ( m_ePackingMode != eMode )
  247. {
  248. // Allow special changes:
  249. // flat -> rgb+a
  250. if ( m_ePackingMode == PCKM_FLAT && eMode == PCKM_RGB_A )
  251. {
  252. m_ePackingMode = eMode;
  253. }
  254. // everything else
  255. else
  256. {
  257. Warning( "*** line error: incompatible packmode change when %d sequences already defined!\n", m_Sequences.Count() );
  258. }
  259. }
  260. }
  261. //-----------------------------------------------------------------------------
  262. //-----------------------------------------------------------------------------
  263. void CDmeAmalgamatedTexture::CreateNewSequence( int mode )
  264. {
  265. m_pCurSequence = CreateElement<CDmeSheetSequence>( "", GetFileId() );
  266. m_pCurSequence->m_nSequenceNumber = m_SequenceCount;
  267. m_SequenceCount++;
  268. SetSequenceType( mode );
  269. m_Sequences.AddToTail( m_pCurSequence );
  270. }
  271. //-----------------------------------------------------------------------------
  272. //-----------------------------------------------------------------------------
  273. int CDmeAmalgamatedTexture::GetSequenceType()
  274. {
  275. return m_pCurSequence->m_eMode;
  276. }
  277. //-----------------------------------------------------------------------------
  278. //-----------------------------------------------------------------------------
  279. void CDmeAmalgamatedTexture::SetSequenceType( int eMode )
  280. {
  281. m_pCurSequence->m_eMode = eMode;
  282. }
  283. //-----------------------------------------------------------------------------
  284. //-----------------------------------------------------------------------------
  285. bool CDmeAmalgamatedTexture::CurrentSequenceExists()
  286. {
  287. return m_pCurSequence != NULL;
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Validate that image packing is correct
  291. //-----------------------------------------------------------------------------
  292. void CDmeAmalgamatedTexture::ValidateImagePacking( CDmeSheetImage *pBitmap, char *pImageName )
  293. {
  294. if ( m_ePackingMode == PCKM_RGB_A )
  295. {
  296. for ( uint16 idx = 0; idx < pBitmap->m_mapSequences.Count(); ++idx )
  297. {
  298. CDmeSheetSequence *pSeq = pBitmap->FindSequence( idx );
  299. Assert( pSeq );
  300. if ( pSeq->m_eMode != SQM_RGBA &&
  301. pSeq->m_eMode != m_pCurSequence->m_eMode )
  302. {
  303. Warning( "*** line error: 'rgb+a' packing cannot pack image '%s' belonging to sequences %d and %d!\n",
  304. pImageName,
  305. pSeq->m_nSequenceNumber,
  306. m_pCurSequence->m_nSequenceNumber );
  307. }
  308. }
  309. }
  310. }
  311. //-----------------------------------------------------------------------------
  312. //-----------------------------------------------------------------------------
  313. void CDmeAmalgamatedTexture::CreateFrame( CUtlVector<char *> &imageNames, float ftime )
  314. {
  315. CDmeSheetSequenceFrame *pNewFrame = CreateElement<CDmeSheetSequenceFrame>( "", GetFileId() );
  316. pNewFrame->m_fDisplayTime = ftime;
  317. for ( int i = 0; i < imageNames.Count(); i++ )
  318. {
  319. Assert( imageNames.Count() <= MAX_IMAGES_PER_FRAME );
  320. AddImage( pNewFrame, imageNames[i] );
  321. }
  322. m_pCurSequence->m_Frames.AddToTail( pNewFrame->GetHandle() );
  323. }
  324. //-----------------------------------------------------------------------------
  325. //-----------------------------------------------------------------------------
  326. void CDmeAmalgamatedTexture::AddImage( CDmeSheetSequenceFrame *pNewSequenceFrame, char *pImageName )
  327. {
  328. // Store the image in the image list, this is a string - bitmap mapping.
  329. CDmeSheetImage *pBitmap = FindImage( pImageName );
  330. if ( !pBitmap )
  331. {
  332. CDmeSheetImage *pBitmap = CreateElement<CDmeSheetImage>( pImageName, GetFileId() );
  333. pBitmap->m_pImage = CreateFloatBitmap( pImageName );
  334. m_ImageList.AddToTail( pBitmap );
  335. }
  336. pBitmap = FindImage( pImageName );
  337. Assert( pBitmap );
  338. pNewSequenceFrame->m_pSheetImages.AddToTail( pBitmap );
  339. ValidateImagePacking( pBitmap, pImageName );
  340. pBitmap->m_mapSequences.AddToTail( m_pCurSequence);
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Calls packimages with different widths to find the best size.
  344. //-----------------------------------------------------------------------------
  345. bool CDmeAmalgamatedTexture::DetermineBestPacking()
  346. {
  347. int nBestWidth = -1;
  348. int nBestSize = (1 << 30 );
  349. int nBestSquareness = ( 1 << 30 ); // how square the texture is
  350. for( int nTryWidth = 2048; nTryWidth >= 64; nTryWidth >>= 1 )
  351. {
  352. bool bSuccess = PackImages( false, nTryWidth );
  353. if ( !bSuccess )
  354. break;
  355. // Msg( "Packing option: %d x %d (%d pixels)\n", m_nWidth.Get(), m_nHeight.Get(), m_nWidth.Get() * m_nHeight.Get() );
  356. bool bPreferThisPack = false;
  357. int thisSize = m_nHeight * m_nWidth;
  358. int thisSquareness = ( m_nWidth.Get() == m_nHeight.Get() ) ? 1 : ( m_nHeight / m_nWidth + m_nWidth / m_nHeight );
  359. if ( thisSize < nBestSize )
  360. {
  361. while ( (nTryWidth >> 1) >= m_nWidth )
  362. nTryWidth >>= 1;
  363. bPreferThisPack = true;
  364. }
  365. else if ( thisSize == nBestSize && thisSquareness < nBestSquareness )
  366. {
  367. bPreferThisPack = true;
  368. }
  369. if ( bPreferThisPack )
  370. {
  371. nBestWidth = nTryWidth;
  372. nBestSize = thisSize;
  373. nBestSquareness = thisSquareness;
  374. }
  375. }
  376. if ( nBestWidth < 0 )
  377. {
  378. Warning( "Packing error: failed to pack images!\n" );
  379. return false;
  380. }
  381. m_nWidth = nBestWidth;
  382. m_nHeight = nBestSize / nBestWidth;
  383. // Msg( "Best option: %d x %d (%d pixels)%s\n", m_nWidth.Get(), m_nHeight.Get(), m_nWidth.Get() * m_nHeight.Get(), ( m_nWidth.Get() == m_nHeight.Get() ) ? " : square texture" : "" );
  384. return true;
  385. }
  386. //-----------------------------------------------------------------------------
  387. //-----------------------------------------------------------------------------
  388. bool CDmeAmalgamatedTexture::PackImages( bool bGenerateImage, int nWidth )
  389. {
  390. if ( !m_pPackedImage )
  391. {
  392. m_pPackedImage = CreateElement< CDmeImage >( GetName(), GetFileId() );
  393. }
  394. switch ( m_ePackingMode )
  395. {
  396. case PCKM_FLAT:
  397. return PackImagesFlat( bGenerateImage, nWidth );
  398. case PCKM_RGB_A:
  399. return PackImagesRGBA( bGenerateImage, nWidth );
  400. case PCKM_INVALID:
  401. default:
  402. return false;
  403. }
  404. }
  405. //-----------------------------------------------------------------------------
  406. //-----------------------------------------------------------------------------
  407. bool CDmeAmalgamatedTexture::PackImagesFlat( bool bGenerateImage, int nWidth )
  408. {
  409. int nMaxWidth = nWidth;
  410. int nMaxHeight = 2048;
  411. // !! bug !! packing algorithm is dumb and no error checking is done!
  412. FloatBitMap_t &output = m_pPackedImage->BeginFloatBitmapModification();
  413. if ( bGenerateImage )
  414. {
  415. output.Init( nMaxWidth, nMaxHeight );
  416. }
  417. int cur_line = 0;
  418. int cur_column = 0;
  419. int next_line = 0;
  420. int max_column_written = 0;
  421. for ( int i = 0; i < m_ImageList.Count(); i++ )
  422. {
  423. CDmeSheetImage &sheetImage = *(m_ImageList[i]);
  424. if ( sheetImage.m_pImage == NULL )
  425. {
  426. Warning( "CDataModel: Image %s was not loaded! Unable to pack.\n", sheetImage.GetName() );
  427. m_pPackedImage->EndFloatBitmapModification();
  428. return false;
  429. }
  430. if ( cur_column + sheetImage.m_pImage->NumCols() > nMaxWidth )
  431. {
  432. // no room!
  433. cur_column = 0;
  434. cur_line = next_line;
  435. next_line = cur_line;
  436. }
  437. // now, pack
  438. if ( ( cur_column + sheetImage.m_pImage->NumCols() > nMaxWidth ) ||
  439. ( cur_line + sheetImage.m_pImage->NumRows() > nMaxHeight ) )
  440. {
  441. m_pPackedImage->EndFloatBitmapModification();
  442. return false; // didn't fit! doh
  443. }
  444. sheetImage.m_XCoord = cur_column;
  445. sheetImage.m_YCoord = cur_line;
  446. if ( bGenerateImage ) // don't actually pack the pixel if we're not keeping them
  447. {
  448. int ic[4];
  449. int nc = sheetImage.m_pImage->ComputeValidAttributeList( ic );
  450. for ( int y = 0; y < sheetImage.m_pImage->NumRows(); y++ )
  451. {
  452. for ( int x = 0; x < sheetImage.m_pImage->NumCols(); x++ )
  453. {
  454. for ( int c = 0; c < nc; c++ )
  455. {
  456. output.Pixel( x + cur_column, y + cur_line, 0, ic[c] ) = sheetImage.m_pImage->Pixel( x, y, 0, ic[c] );
  457. }
  458. }
  459. }
  460. }
  461. next_line = MAX( next_line, cur_line + sheetImage.m_pImage->NumRows() );
  462. cur_column += sheetImage.m_pImage->NumCols();
  463. max_column_written = MAX( max_column_written, cur_column );
  464. }
  465. // now, truncate height
  466. int h = 1;
  467. for( h; h < next_line; h *= 2 )
  468. ;
  469. // truncate width;
  470. int w = 1;
  471. for( 1; w < max_column_written; w *= 2 )
  472. ;
  473. if ( bGenerateImage )
  474. {
  475. output.Crop( 0, 0, 0, w, h, 1 );
  476. }
  477. // Store these for UV calculation later on
  478. m_nHeight = h;
  479. m_nWidth = w;
  480. m_pPackedImage->EndFloatBitmapModification();
  481. return true;
  482. }
  483. //-----------------------------------------------------------------------------
  484. //-----------------------------------------------------------------------------
  485. bool CDmeAmalgamatedTexture::PackImagesRGBA( bool bGenerateImage, int nWidth )
  486. {
  487. int nMaxWidth = nWidth;
  488. int nMaxHeight = 2048;
  489. // !! bug !! packing algorithm is dumb and no error checking is done!
  490. FloatBitMap_t &output = m_pPackedImage->BeginFloatBitmapModification();
  491. if ( bGenerateImage )
  492. {
  493. output.Init( nMaxWidth, nMaxHeight );
  494. }
  495. int cur_line[2] = {0};
  496. int cur_column[2] = {0};
  497. int next_line[2] = {0};
  498. int max_column_written[2] = {0};
  499. bool bPackingRGBA = true;
  500. for ( int i = 0; i < m_ImageList.Count(); i++ )
  501. {
  502. CDmeSheetImage &sheetImage = *( m_ImageList[i] );
  503. if ( sheetImage.m_pImage == NULL )
  504. {
  505. Warning( "CDataModel: Image %s was not loaded! Unable to pack.\n", sheetImage.GetName() );
  506. m_pPackedImage->EndFloatBitmapModification();
  507. return false;
  508. }
  509. int idxfrm;
  510. CDmeSheetSequence *pSequence = sheetImage.FindSequence( 0 );
  511. Assert( pSequence );
  512. int eMode = pSequence->m_eMode;
  513. switch ( eMode )
  514. {
  515. case SQM_RGB:
  516. idxfrm = 0;
  517. bPackingRGBA = false;
  518. break;
  519. case SQM_ALPHA:
  520. idxfrm = 1;
  521. bPackingRGBA = false;
  522. break;
  523. case SQM_RGBA:
  524. if ( !bPackingRGBA )
  525. {
  526. Msg( "*** error when packing 'rgb+a', bad sequence %d encountered for image '%s' after all rgba frames packed!\n",
  527. pSequence->m_nSequenceNumber,
  528. m_ImageList[i]->GetName() );
  529. m_pPackedImage->EndFloatBitmapModification();
  530. return false;
  531. }
  532. idxfrm = 0;
  533. break;
  534. default:
  535. {
  536. Msg( "*** error when packing 'rgb+a', bad sequence %d encountered for image '%s'!\n",
  537. pSequence->m_nSequenceNumber,
  538. m_ImageList[i]->GetName() );
  539. m_pPackedImage->EndFloatBitmapModification();
  540. return false;
  541. }
  542. }
  543. if ( cur_column[idxfrm] + sheetImage.m_pImage->NumCols() > nMaxWidth )
  544. {
  545. // no room!
  546. cur_column[idxfrm] = 0;
  547. cur_line[idxfrm] = next_line[idxfrm];
  548. next_line[idxfrm] = cur_line[idxfrm];
  549. }
  550. // now, pack
  551. if ( ( cur_column[idxfrm] + sheetImage.m_pImage->NumCols() > nMaxWidth ) ||
  552. ( cur_line[idxfrm] + sheetImage.m_pImage->NumRows() > nMaxHeight ) )
  553. {
  554. return false; // didn't fit! doh
  555. }
  556. sheetImage.m_XCoord = cur_column[idxfrm];
  557. sheetImage.m_YCoord = cur_line[idxfrm];
  558. if ( bGenerateImage ) // don't actually pack the pixel if we're not keeping them
  559. {
  560. for ( int y = 0; y < sheetImage.m_pImage->NumRows(); y++ )
  561. {
  562. for ( int x = 0; x < sheetImage.m_pImage->NumCols(); x++ )
  563. {
  564. for ( int c = 0; c < 4; c++ )
  565. {
  566. switch ( eMode )
  567. {
  568. case SQM_RGB:
  569. if ( c < 3 )
  570. goto setpx;
  571. break;
  572. case SQM_ALPHA:
  573. if ( c == 3 )
  574. goto setpx;
  575. break;
  576. case SQM_RGBA:
  577. if ( c < 4 )
  578. goto setpx;
  579. break;
  580. setpx:
  581. output.Pixel( x + cur_column[idxfrm], y + cur_line[idxfrm], 0, c ) = sheetImage.m_pImage->Pixel(x, y, 0, c);
  582. break;
  583. }
  584. }
  585. }
  586. }
  587. }
  588. next_line[idxfrm] = MAX( next_line[idxfrm], cur_line[idxfrm] + sheetImage.m_pImage->NumRows() );
  589. cur_column[idxfrm] += sheetImage.m_pImage->NumCols();
  590. max_column_written[idxfrm] = MAX( max_column_written[idxfrm], cur_column[idxfrm] );
  591. if ( bPackingRGBA )
  592. {
  593. cur_line[1] = cur_line[0];
  594. cur_column[1] = cur_column[0];
  595. next_line[1] = next_line[0];
  596. max_column_written[1] = max_column_written[0];
  597. }
  598. }
  599. // now, truncate height
  600. int h = 1;
  601. for ( int idxfrm = 0; idxfrm < 2; ++idxfrm )
  602. {
  603. for ( h; h < next_line[idxfrm]; h *= 2 )
  604. continue;
  605. }
  606. // truncate width;
  607. int w = 1;
  608. for ( int idxfrm = 0; idxfrm < 2; ++idxfrm )
  609. {
  610. for ( w; w < max_column_written[idxfrm]; w *= 2 )
  611. continue;
  612. }
  613. if ( bGenerateImage )
  614. {
  615. output.Crop( 0, 0, 0, w, h, 1 );
  616. }
  617. // Store these for UV calculation later on
  618. m_nHeight = h;
  619. m_nWidth = w;
  620. m_pPackedImage->EndFloatBitmapModification();
  621. return true;
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Write out .sht file.
  625. //-----------------------------------------------------------------------------
  626. bool CDmeAmalgamatedTexture::WriteTGA( const char *pFileName )
  627. {
  628. if ( !pFileName )
  629. goto tgaWriteFailed;
  630. if ( !m_pPackedImage )
  631. goto tgaWriteFailed;
  632. if ( !m_pPackedImage->FloatBitmap()->WriteTGAFile( pFileName ) )
  633. goto tgaWriteFailed;
  634. Msg( "Ok: successfully saved TGA \"%s\"\n", pFileName );
  635. return true;
  636. tgaWriteFailed:
  637. Msg( "Error: failed to save TGA \"%s\"!\n", pFileName );
  638. return false;
  639. }
  640. //-----------------------------------------------------------------------------
  641. // Write out .sht file.
  642. //-----------------------------------------------------------------------------
  643. void CDmeAmalgamatedTexture::WriteFile( const char *pFileName, bool bVerbose )
  644. {
  645. if ( !pFileName )
  646. {
  647. Msg( "Error: No output filename set!\n" );
  648. return;
  649. }
  650. COutputFile Outfile( pFileName );
  651. if ( !Outfile.IsOk() )
  652. {
  653. Msg( "Error: failed to write SHT \"%s\"!\n", pFileName );
  654. return;
  655. }
  656. Outfile.PutInt( 1 ); // version #
  657. Outfile.PutInt( m_Sequences.Count() );
  658. // Debugging.
  659. if ( bVerbose )
  660. {
  661. Msg( "1\n");
  662. Msg( "m_Sequences.Count() %d\n", m_Sequences.Count());
  663. }
  664. for ( int i = 0; i < m_Sequences.Count(); i++ )
  665. {
  666. Outfile.PutInt( m_Sequences[i]->m_nSequenceNumber );
  667. int nSeqFlags = 0;
  668. if ( m_Sequences[i]->m_Clamp )
  669. {
  670. nSeqFlags |= SEQ_FLAG_CLAMP;
  671. }
  672. if ( m_Sequences[i]->m_eMode == SQM_RGB )
  673. {
  674. nSeqFlags |= SEQ_FLAG_NO_ALPHA;
  675. }
  676. else if ( m_Sequences[i]->m_eMode == SQM_ALPHA )
  677. {
  678. nSeqFlags |= SEQ_FLAG_NO_COLOR;
  679. }
  680. Outfile.PutInt( nSeqFlags );
  681. Outfile.PutInt( m_Sequences[i]->m_Frames.Count() );
  682. // write total sequence length
  683. float fTotal = 0.0;
  684. for ( int j = 0; j < m_Sequences[i]->m_Frames.Count(); j++ )
  685. {
  686. fTotal += m_Sequences[i]->m_Frames[j]->m_fDisplayTime;
  687. }
  688. Outfile.PutFloat( fTotal );
  689. // Debugging.
  690. if ( bVerbose )
  691. {
  692. Msg( "m_Sequences[%d]->m_nSequenceNumber %d\n", i, m_Sequences[i]->m_nSequenceNumber.Get() );
  693. Msg( "m_Sequences[%d]->m_Clamp %d\n", i, m_Sequences[i]->m_Clamp?1:0 );
  694. Msg( "m_Sequences[%d] flags %d\n", i, nSeqFlags );
  695. Msg( "m_Sequences[%d]->m_Frames.Count() %d\n", i, m_Sequences[i]->m_Frames.Count());
  696. Msg( "fTotal %f\n", fTotal );
  697. }
  698. for( int j = 0; j < m_Sequences[i]->m_Frames.Count(); j++ )
  699. {
  700. Outfile.PutFloat( m_Sequences[i]->m_Frames[j]->m_fDisplayTime );
  701. if ( bVerbose )
  702. {
  703. Msg( "m_Sequences[%d]->m_Frames[%d]->m_fDisplayTime %f\n", i, j, m_Sequences[i]->m_Frames[j]->m_fDisplayTime.Get() );
  704. }
  705. // output texture coordinates
  706. Assert( m_Sequences[i]->m_Frames[j]->m_pSheetImages.Count() > 0 );
  707. for( int t = 0; t < m_Sequences[i]->m_Frames[j]->m_pSheetImages.Count(); t++ )
  708. {
  709. //xmin
  710. Outfile.PutFloat( UCoord( m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_XCoord ) );
  711. //ymin
  712. Outfile.PutFloat( VCoord( m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_YCoord ) );
  713. //xmax
  714. Outfile.PutFloat(
  715. UCoord( m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_XCoord +
  716. m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_pImage->NumCols() - 1 ));
  717. //ymax
  718. Outfile.PutFloat(
  719. VCoord( m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_YCoord +
  720. m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_pImage->NumRows() - 1 ));
  721. // Debugging.
  722. if ( bVerbose )
  723. {
  724. Msg( "xmin %f\n", UCoord( m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_XCoord ) );
  725. Msg( "ymin %f\n", VCoord( m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_YCoord ) );
  726. Msg( "xmax %f\n", UCoord( m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_XCoord +
  727. m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_pImage->NumCols() - 1 ) );
  728. Msg( "ymax %f\n", VCoord( m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_YCoord +
  729. m_Sequences[i]->m_Frames[j]->m_pSheetImages[t]->m_pImage->NumRows() - 1 ) );
  730. }
  731. }
  732. // Sequenceframes must have 4 entries in the .sht file.
  733. // We store up to 4 in the dme elements
  734. // Add in the missing entries as dummy data.
  735. for( int t = m_Sequences[i]->m_Frames[j]->m_pSheetImages.Count(); t < MAX_IMAGES_PER_FRAME; t++ )
  736. {
  737. Outfile.PutFloat(0.0);
  738. Outfile.PutFloat(0.0);
  739. Outfile.PutFloat(0.0);
  740. Outfile.PutFloat(0.0);
  741. // Debugging.
  742. if ( bVerbose )
  743. {
  744. Msg( "xmin %f\nymin %f\nxmax %f\nymax %f\n", 0.0, 0.0, 0.0 ,0.0 );
  745. }
  746. }
  747. }
  748. }
  749. Msg( "Ok: successfully saved SHT \"%s\"\n", pFileName );
  750. }
  751. //-----------------------------------------------------------------------------
  752. // Write out .sht file.
  753. //-----------------------------------------------------------------------------
  754. void *CDmeAmalgamatedTexture::WriteFile( CResourceStream *pStream, ResourceId_t nTextureResourceId )
  755. {
  756. Sheet_t *pSheet = pStream->Allocate< Sheet_t >( 1 );
  757. pSheet->m_hTexture.WriteReference( nTextureResourceId );
  758. int nCount = m_Sequences.Count();
  759. pSheet->m_Sequences = pStream->Allocate< SheetSequence_t >( nCount );
  760. for ( int i = 0; i < nCount; i++ )
  761. {
  762. CDmeSheetSequence *pDmeSeq = m_Sequences[i];
  763. SheetSequence_t &seq = pSheet->m_Sequences[i];
  764. seq.m_nId = pDmeSeq->m_nSequenceNumber;
  765. seq.m_bClamp = pDmeSeq->m_Clamp;
  766. int nFrameCount = pDmeSeq->m_Frames.Count();
  767. seq.m_Frames = pStream->Allocate< SheetSequenceFrame_t >( nFrameCount );
  768. seq.m_flTotalTime = 0.0;
  769. for( int j = 0; j < nFrameCount; j++ )
  770. {
  771. CDmeSheetSequenceFrame *pDmeFrame = pDmeSeq->m_Frames[j];
  772. SheetSequenceFrame_t &frame = seq.m_Frames[i];
  773. // Compute total sequence length
  774. seq.m_flTotalTime += pDmeFrame->m_fDisplayTime;
  775. frame.m_flDisplayTime = pDmeFrame->m_fDisplayTime;
  776. int nImageCount = pDmeFrame->m_pSheetImages.Count();
  777. frame.m_Images = pStream->Allocate< SheetFrameImage_t >( nImageCount );
  778. // output texture coordinates
  779. Assert( nImageCount > 0 );
  780. for( int t = 0; t < nImageCount; t++ )
  781. {
  782. CDmeSheetImage *pDmeImage = pDmeFrame->m_pSheetImages[t];
  783. SheetFrameImage_t &image = frame.m_Images[t];
  784. image.uv[0].x = UCoord( pDmeImage->m_XCoord );
  785. image.uv[0].y = VCoord( pDmeImage->m_YCoord );
  786. image.uv[1].x = UCoord( pDmeImage->m_XCoord + pDmeImage->m_pImage->NumCols() - 1 );
  787. image.uv[1].y = VCoord( pDmeImage->m_YCoord + pDmeImage->m_pImage->NumRows() - 1 );
  788. }
  789. }
  790. }
  791. return pSheet;
  792. }
  793. //-----------------------------------------------------------------------------
  794. //-----------------------------------------------------------------------------
  795. CDmeSheetImage *CDmeAmalgamatedTexture::FindImage( const char *pImageName )
  796. {
  797. int nCount = m_ImageList.Count();
  798. for ( int i = 0; i < nCount; ++i )
  799. {
  800. CDmeSheetImage *pImage = m_ImageList[i];
  801. if ( !Q_stricmp( pImageName, pImage->GetName() ) )
  802. return pImage;
  803. }
  804. return NULL;
  805. }