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.

2615 lines
71 KiB

  1. //========= Copyright (c) 1996-2009, Valve Corporation, All rights reserved. ============//
  2. //
  3. // NOTE: To make use of this file, g_pFullFileSystem must be defined, or you can modify
  4. // this source to take an IFileSystem * as input.
  5. //
  6. //=======================================================================================//
  7. // @note Tom Bui: we need to use fopen below in the jpeg code, so we can't have this on...
  8. #ifdef PROTECTED_THINGS_ENABLE
  9. #undef fopen
  10. #endif
  11. #if defined( WIN32 ) && !defined( _X360 )
  12. #include <windows.h> // SRC only!!
  13. #elif defined( POSIX )
  14. #include <stdio.h>
  15. #include <sys/stat.h>
  16. #ifdef OSX
  17. #include <copyfile.h>
  18. #endif
  19. #endif
  20. #include "imageutils.h"
  21. #include "filesystem.h"
  22. #include "utlbuffer.h"
  23. #include "bitmap/bitmap.h"
  24. #include "vtf/vtf.h"
  25. // clang3 on OSX folks the attribute into the prototype, causing a compile failure
  26. // filed radar bug 10397783
  27. #if ( __clang_major__ == 3 )
  28. #include <setjmp.h>
  29. extern void longjmp( jmp_buf, int ) __attribute__((noreturn));
  30. #endif
  31. #ifdef ENGINE_DLL
  32. #include "common.h"
  33. #elif CLIENT_DLL
  34. // @note Tom Bui: instead of forcing the project to include EngineInterface.h...
  35. #include "cdll_int.h"
  36. // engine interface singleton accessors
  37. extern IVEngineClient *engine;
  38. extern class IGameUIFuncs *gameuifuncs;
  39. extern class IEngineSound *enginesound;
  40. extern class IMatchmaking *matchmaking;
  41. extern class IXboxSystem *xboxsystem;
  42. extern class IAchievementMgr *achievementmgr;
  43. extern class CSteamAPIContext *steamapicontext;
  44. #elif REPLAY_DLL
  45. #include "replay/ienginereplay.h"
  46. extern IEngineReplay *g_pEngine;
  47. #elif ENGINE_DLL
  48. #include "engineinterface.h"
  49. #elif defined(CLIENT_DLL) || defined(GAME_DLL)
  50. #include "cdll_int.h"
  51. extern IVEngineClient *engine;
  52. #endif
  53. // use the JPEGLIB_USE_STDIO define so that we can read in jpeg's from outside the game directory tree.
  54. #define JPEGLIB_USE_STDIO
  55. #include "jpeglib/jpeglib.h"
  56. #undef JPEGLIB_USE_STDIO
  57. #include "../thirdparty/libpng-1.5.2/png.h"
  58. #include "../thirdparty/libpng-1.5.2/pngstruct.h"
  59. #include <setjmp.h>
  60. // clang3 on OSX folds the attribute into the prototype, causing a compile failure
  61. // filed radar bug 10397783
  62. #if ( __clang_major__ == 3 )
  63. extern void longjmp( jmp_buf, int ) __attribute__((noreturn));
  64. #endif
  65. #include "bitmap/tgawriter.h"
  66. #include "ivtex.h"
  67. #ifdef WIN32
  68. #include <io.h>
  69. #endif
  70. #ifdef OSX
  71. #include <copyfile.h>
  72. #endif
  73. #ifndef WIN32
  74. #define DeleteFile(s) remove(s)
  75. #endif
  76. #if defined( _X360 )
  77. #include "xbox/xbox_win32stubs.h"
  78. #endif
  79. #if !defined( _GAMECONSOLE ) && ( defined(GAME_DLL) || defined(CLIENT_DLL) )
  80. // Protobuf headers interfere with the valve min/max/malloc overrides. so we need to do all
  81. // this funky wrapping to make the include happy.
  82. #include <tier0/valve_minmax_off.h>
  83. #include "base_gcmessages.pb.h"
  84. #include <tier0/valve_minmax_on.h>
  85. #endif //!defined( _GAMECONSOLE )
  86. // memdbgon must be the last include file in a .cpp file!!!
  87. #include <tier0/memdbgon.h>
  88. //-----------------------------------------------------------------------------
  89. // Purpose:
  90. //-----------------------------------------------------------------------------
  91. struct ValveJpegErrorHandler_t
  92. {
  93. // The default manager
  94. struct jpeg_error_mgr m_Base;
  95. // For handling any errors
  96. jmp_buf m_ErrorContext;
  97. };
  98. #define JPEG_OUTPUT_BUF_SIZE 4096
  99. struct JPEGDestinationManager_t
  100. {
  101. struct jpeg_destination_mgr pub; // public fields
  102. CUtlBuffer *pBuffer; // target/final buffer
  103. byte *buffer; // start of temp buffer
  104. };
  105. //-----------------------------------------------------------------------------
  106. // Purpose: We'll override the default error handler so we can deal with errors without having to exit the engine
  107. //-----------------------------------------------------------------------------
  108. static void ValveJpegErrorHandler( j_common_ptr cinfo )
  109. {
  110. ValveJpegErrorHandler_t *pError = reinterpret_cast< ValveJpegErrorHandler_t * >( cinfo->err );
  111. char buffer[ JMSG_LENGTH_MAX ];
  112. /* Create the message */
  113. ( *cinfo->err->format_message )( cinfo, buffer );
  114. Warning( "%s\n", buffer );
  115. // Bail
  116. longjmp( pError->m_ErrorContext, 1 );
  117. }
  118. class CJpegSourceMgr : public jpeg_source_mgr
  119. {
  120. public:
  121. CJpegSourceMgr()
  122. {
  123. this->init_source = &CJpegSourceMgr::imp_init_source;
  124. this->fill_input_buffer = &CJpegSourceMgr::imp_fill_input_buffer;
  125. this->skip_input_data = &CJpegSourceMgr::imp_skip_input_data;
  126. this->resync_to_restart = &CJpegSourceMgr::imp_resync_to_restart;
  127. this->term_source = &CJpegSourceMgr::imp_term_source;
  128. this->next_input_byte = 0;
  129. this->bytes_in_buffer = 0;
  130. }
  131. static void error_exit ( j_common_ptr cinfo )
  132. {
  133. /* Always display the message */
  134. (*cinfo->err->output_message) (cinfo);
  135. /* Let the memory manager delete any temp files before we die */
  136. jpeg_destroy(cinfo);
  137. //exit( EXIT_FAILURE );
  138. // FIXME: Can't we get a better error than this?
  139. }
  140. static void imp_init_source(j_decompress_ptr cinfo)
  141. {
  142. }
  143. static boolean imp_fill_input_buffer(j_decompress_ptr cinfo)
  144. {
  145. Assert( false ); // They should never need to call these functions since we give them all the data up front.
  146. return 0;
  147. }
  148. static void imp_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
  149. {
  150. Assert( false ); // They should never need to call these functions since we give them all the data up front.
  151. }
  152. static boolean imp_resync_to_restart(j_decompress_ptr cinfo, int desired)
  153. {
  154. Assert( false ); // They should never need to call these functions since we give them all the data up front.
  155. return false;
  156. }
  157. static void imp_term_source(j_decompress_ptr cinfo)
  158. {
  159. }
  160. public:
  161. // CUtlVector<char> m_Data;
  162. };
  163. // convert the JPEG file given to a TGA file at the given output path.
  164. ConversionErrorType ImgUtl_ConvertJPEGToTGA( const char *jpegpath, const char *tgaPath, bool bRequirePowerOfTwo )
  165. {
  166. #if !defined( _X360 )
  167. //
  168. // !FIXME! This really probably should use ImgUtl_ReadJPEGAsRGBA, to avoid duplicated code.
  169. //
  170. struct jpeg_decompress_struct jpegInfo;
  171. struct ValveJpegErrorHandler_t jerr;
  172. JSAMPROW row_pointer[1];
  173. int row_stride;
  174. int cur_row = 0;
  175. // image attributes
  176. int image_height;
  177. int image_width;
  178. // open the jpeg image file.
  179. FILE *infile = fopen(jpegpath, "rb");
  180. if (infile == NULL)
  181. {
  182. return CE_CANT_OPEN_SOURCE_FILE;
  183. }
  184. // setup error to print to stderr.
  185. jpegInfo.err = jpeg_std_error(&jerr.m_Base);
  186. jpegInfo.err->error_exit = &ValveJpegErrorHandler;
  187. // create the decompress struct.
  188. jpeg_create_decompress(&jpegInfo);
  189. if ( setjmp( jerr.m_ErrorContext ) )
  190. {
  191. // Get here if there is any error
  192. jpeg_destroy_decompress( &jpegInfo );
  193. fclose(infile);
  194. return CE_ERROR_PARSING_SOURCE;
  195. }
  196. jpeg_stdio_src(&jpegInfo, infile);
  197. // read in the jpeg header and make sure that's all good.
  198. if (jpeg_read_header(&jpegInfo, TRUE) != JPEG_HEADER_OK)
  199. {
  200. fclose(infile);
  201. return CE_ERROR_PARSING_SOURCE;
  202. }
  203. // start the decompress with the jpeg engine.
  204. if ( !jpeg_start_decompress(&jpegInfo) )
  205. {
  206. jpeg_destroy_decompress(&jpegInfo);
  207. fclose(infile);
  208. return CE_ERROR_PARSING_SOURCE;
  209. }
  210. // Check for valid width and height (ie. power of 2 and print out an error and exit if not).
  211. if ( bRequirePowerOfTwo && ( !IsPowerOfTwo(jpegInfo.image_height) || !IsPowerOfTwo(jpegInfo.image_width) )
  212. || jpegInfo.output_components != 3 )
  213. {
  214. jpeg_destroy_decompress(&jpegInfo);
  215. fclose( infile );
  216. return CE_SOURCE_FILE_SIZE_NOT_SUPPORTED;
  217. }
  218. // now that we've started the decompress with the jpeg lib, we have the attributes of the
  219. // image ready to be read out of the decompress struct.
  220. row_stride = jpegInfo.output_width * jpegInfo.output_components;
  221. image_height = jpegInfo.image_height;
  222. image_width = jpegInfo.image_width;
  223. int mem_required = jpegInfo.image_height * jpegInfo.image_width * jpegInfo.output_components;
  224. // allocate the memory to read the image data into.
  225. unsigned char *buf = (unsigned char *)malloc(mem_required);
  226. if (buf == NULL)
  227. {
  228. jpeg_destroy_decompress(&jpegInfo);
  229. fclose(infile);
  230. return CE_MEMORY_ERROR;
  231. }
  232. // read in all the scan lines of the image into our image data buffer.
  233. bool working = true;
  234. while (working && (jpegInfo.output_scanline < jpegInfo.output_height))
  235. {
  236. row_pointer[0] = &(buf[cur_row * row_stride]);
  237. if ( !jpeg_read_scanlines(&jpegInfo, row_pointer, 1) )
  238. {
  239. working = false;
  240. }
  241. ++cur_row;
  242. }
  243. if (!working)
  244. {
  245. free(buf);
  246. jpeg_destroy_decompress(&jpegInfo);
  247. fclose(infile);
  248. return CE_ERROR_PARSING_SOURCE;
  249. }
  250. jpeg_finish_decompress(&jpegInfo);
  251. fclose(infile);
  252. // ok, at this point we have read in the JPEG image to our buffer, now we need to write it out as a TGA file.
  253. CUtlBuffer outBuf;
  254. bool bRetVal = TGAWriter::WriteToBuffer( buf, outBuf, image_width, image_height, IMAGE_FORMAT_RGB888, IMAGE_FORMAT_RGB888 );
  255. if ( bRetVal )
  256. {
  257. if ( !g_pFullFileSystem->WriteFile( tgaPath, NULL, outBuf ) )
  258. {
  259. bRetVal = false;
  260. }
  261. }
  262. free(buf);
  263. return bRetVal ? CE_SUCCESS : CE_ERROR_WRITING_OUTPUT_FILE;
  264. #else
  265. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  266. #endif
  267. }
  268. // convert the bmp file given to a TGA file at the given destination path.
  269. ConversionErrorType ImgUtl_ConvertBMPToTGA(const char *bmpPath, const char *tgaPath)
  270. {
  271. if ( !IsPC() )
  272. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  273. #ifdef WIN32
  274. int nWidth, nHeight;
  275. ConversionErrorType result;
  276. unsigned char *pBufRGBA = ImgUtl_ReadBMPAsRGBA( bmpPath, nWidth, nHeight, result );
  277. if ( result != CE_SUCCESS)
  278. {
  279. Assert( !pBufRGBA );
  280. free( pBufRGBA );
  281. return result;
  282. }
  283. Assert( pBufRGBA );
  284. // write out the TGA file using the RGB data buffer.
  285. CUtlBuffer outBuf;
  286. bool retval = TGAWriter::WriteToBuffer(pBufRGBA, outBuf, nWidth, nHeight, IMAGE_FORMAT_RGBA8888, IMAGE_FORMAT_RGB888);
  287. free( pBufRGBA );
  288. if ( retval )
  289. {
  290. if ( !g_pFullFileSystem->WriteFile( tgaPath, NULL, outBuf ) )
  291. {
  292. retval = false;
  293. }
  294. }
  295. return retval ? CE_SUCCESS : CE_ERROR_WRITING_OUTPUT_FILE;
  296. #else // WIN32
  297. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  298. #endif
  299. }
  300. unsigned char *ImgUtl_ReadVTFAsRGBA( const char *vtfPath, int &width, int &height, ConversionErrorType &errcode )
  301. {
  302. // Just load the whole file into a memory buffer
  303. CUtlBuffer bufFileContents;
  304. if ( !g_pFullFileSystem->ReadFile( vtfPath, NULL, bufFileContents ) )
  305. {
  306. errcode = CE_CANT_OPEN_SOURCE_FILE;
  307. return NULL;
  308. }
  309. IVTFTexture *pVTFTexture = CreateVTFTexture();
  310. if ( !pVTFTexture->Unserialize( bufFileContents ) )
  311. {
  312. DestroyVTFTexture( pVTFTexture );
  313. errcode = CE_ERROR_PARSING_SOURCE;
  314. return NULL;
  315. }
  316. width = pVTFTexture->Width();
  317. height = pVTFTexture->Height();
  318. pVTFTexture->ConvertImageFormat( IMAGE_FORMAT_RGBA8888, false );
  319. int nMemSize = ImageLoader::GetMemRequired( width, height, 1, IMAGE_FORMAT_RGBA8888, false );
  320. unsigned char *pMemImage = (unsigned char *)malloc(nMemSize);
  321. if ( pMemImage == NULL )
  322. {
  323. DestroyVTFTexture( pVTFTexture );
  324. errcode = CE_MEMORY_ERROR;
  325. return NULL;
  326. }
  327. Q_memcpy( pMemImage, pVTFTexture->ImageData(), nMemSize );
  328. DestroyVTFTexture( pVTFTexture );
  329. errcode = CE_SUCCESS;
  330. return pMemImage;
  331. }
  332. // read a TGA header from the current point in the file stream.
  333. static void ImgUtl_ReadTGAHeader(FILE *infile, TGAHeader &header)
  334. {
  335. if (infile == NULL)
  336. {
  337. return;
  338. }
  339. fread(&header.identsize, sizeof(header.identsize), 1, infile);
  340. fread(&header.colourmaptype, sizeof(header.colourmaptype), 1, infile);
  341. fread(&header.imagetype, sizeof(header.imagetype), 1, infile);
  342. fread(&header.colourmapstart, sizeof(header.colourmapstart), 1, infile);
  343. fread(&header.colourmaplength, sizeof(header.colourmaplength), 1, infile);
  344. fread(&header.colourmapbits, sizeof(header.colourmapbits), 1, infile);
  345. fread(&header.xstart, sizeof(header.xstart), 1, infile);
  346. fread(&header.ystart, sizeof(header.ystart), 1, infile);
  347. fread(&header.width, sizeof(header.width), 1, infile);
  348. fread(&header.height, sizeof(header.height), 1, infile);
  349. fread(&header.bits, sizeof(header.bits), 1, infile);
  350. fread(&header.descriptor, sizeof(header.descriptor), 1, infile);
  351. }
  352. // write a TGA header to the current point in the file stream.
  353. static void WriteTGAHeader(FILE *outfile, TGAHeader &header)
  354. {
  355. if (outfile == NULL)
  356. {
  357. return;
  358. }
  359. fwrite(&header.identsize, sizeof(header.identsize), 1, outfile);
  360. fwrite(&header.colourmaptype, sizeof(header.colourmaptype), 1, outfile);
  361. fwrite(&header.imagetype, sizeof(header.imagetype), 1, outfile);
  362. fwrite(&header.colourmapstart, sizeof(header.colourmapstart), 1, outfile);
  363. fwrite(&header.colourmaplength, sizeof(header.colourmaplength), 1, outfile);
  364. fwrite(&header.colourmapbits, sizeof(header.colourmapbits), 1, outfile);
  365. fwrite(&header.xstart, sizeof(header.xstart), 1, outfile);
  366. fwrite(&header.ystart, sizeof(header.ystart), 1, outfile);
  367. fwrite(&header.width, sizeof(header.width), 1, outfile);
  368. fwrite(&header.height, sizeof(header.height), 1, outfile);
  369. fwrite(&header.bits, sizeof(header.bits), 1, outfile);
  370. fwrite(&header.descriptor, sizeof(header.descriptor), 1, outfile);
  371. }
  372. // reads in a TGA file and converts it to 32 bit RGBA color values in a memory buffer.
  373. unsigned char * ImgUtl_ReadTGAAsRGBA(const char *tgaPath, int &width, int &height, ConversionErrorType &errcode, TGAHeader &tgaHeader )
  374. {
  375. FILE *tgaFile = fopen(tgaPath, "rb");
  376. if (tgaFile == NULL)
  377. {
  378. errcode = CE_CANT_OPEN_SOURCE_FILE;
  379. return NULL;
  380. }
  381. // read header for TGA file.
  382. ImgUtl_ReadTGAHeader(tgaFile, tgaHeader);
  383. if (
  384. ( tgaHeader.imagetype != 2 ) // image type 2 is uncompressed RGB, other types not supported.
  385. || ( tgaHeader.descriptor & 0x10 ) // Origin on righthand side (flipped horizontally from common sense) --- nobody ever uses this
  386. || ( tgaHeader.bits != 24 && tgaHeader.bits != 32 ) // Must be 24- ot 32-bit
  387. )
  388. {
  389. fclose(tgaFile);
  390. errcode = CE_SOURCE_FILE_TGA_FORMAT_NOT_SUPPORTED;
  391. return NULL;
  392. }
  393. int tgaDataSize = tgaHeader.width * tgaHeader.height * tgaHeader.bits / 8;
  394. unsigned char *tgaData = (unsigned char *)malloc(tgaDataSize);
  395. if (tgaData == NULL)
  396. {
  397. fclose(tgaFile);
  398. errcode = CE_MEMORY_ERROR;
  399. return NULL;
  400. }
  401. fread(tgaData, 1, tgaDataSize, tgaFile);
  402. fclose(tgaFile);
  403. width = tgaHeader.width;
  404. height = tgaHeader.height;
  405. int numPixels = tgaHeader.width * tgaHeader.height;
  406. if (tgaHeader.bits == 24)
  407. {
  408. // image needs to be converted to a 32-bit image.
  409. unsigned char *retBuf = (unsigned char *)malloc(numPixels * 4);
  410. if (retBuf == NULL)
  411. {
  412. free(tgaData);
  413. errcode = CE_MEMORY_ERROR;
  414. return NULL;
  415. }
  416. // convert from BGR to RGBA color format.
  417. for (int index = 0; index < numPixels; ++index)
  418. {
  419. retBuf[index * 4] = tgaData[index * 3 + 2];
  420. retBuf[index * 4 + 1] = tgaData[index * 3 + 1];
  421. retBuf[index * 4 + 2] = tgaData[index * 3];
  422. retBuf[index * 4 + 3] = 0xff;
  423. }
  424. free(tgaData);
  425. tgaData = retBuf;
  426. tgaHeader.bits = 32;
  427. }
  428. else if (tgaHeader.bits == 32)
  429. {
  430. // Swap blue and red to convert BGR -> RGB
  431. for (int index = 0; index < numPixels; ++index)
  432. {
  433. V_swap( tgaData[index*4], tgaData[index*4 + 2] );
  434. }
  435. }
  436. // Flip image vertically if necessary
  437. if ( !( tgaHeader.descriptor & 0x20 ) )
  438. {
  439. int y0 = 0;
  440. int y1 = height-1;
  441. int iStride = width*4;
  442. while ( y0 < y1 )
  443. {
  444. unsigned char *ptr0 = tgaData + y0*iStride;
  445. unsigned char *ptr1 = tgaData + y1*iStride;
  446. for ( int i = 0 ; i < iStride ; ++i )
  447. {
  448. V_swap( ptr0[i], ptr1[i] );
  449. }
  450. ++y0;
  451. --y1;
  452. }
  453. tgaHeader.descriptor |= 0x20;
  454. }
  455. errcode = CE_SUCCESS;
  456. return tgaData;
  457. }
  458. unsigned char *ImgUtl_ReadJPEGAsRGBA( const char *jpegPath, int &width, int &height, ConversionErrorType &errcode )
  459. {
  460. #if !defined( _X360 )
  461. struct jpeg_decompress_struct jpegInfo;
  462. struct ValveJpegErrorHandler_t jerr;
  463. JSAMPROW row_pointer[1];
  464. int row_stride;
  465. int cur_row = 0;
  466. // image attributes
  467. int image_height;
  468. int image_width;
  469. // open the jpeg image file.
  470. FILE *infile = fopen(jpegPath, "rb");
  471. if (infile == NULL)
  472. {
  473. errcode = CE_CANT_OPEN_SOURCE_FILE;
  474. return NULL;
  475. }
  476. //CJpegSourceMgr src;
  477. //FileHandle_t fileHandle = g_pFullFileSystem->Open( jpegPath, "rb" );
  478. //if ( fileHandle == FILESYSTEM_INVALID_HANDLE )
  479. //{
  480. // errcode = CE_CANT_OPEN_SOURCE_FILE;
  481. // return NULL;
  482. //}
  483. //if ( !src.Init( g_pFullFileSystem, fileHandle ) ) {
  484. // errcode = CE_CANT_OPEN_SOURCE_FILE;
  485. // g_pFullFileSystem->Close( fileHandle );
  486. // return NULL;
  487. //}
  488. // setup error to print to stderr.
  489. memset( &jpegInfo, 0, sizeof( jpegInfo ) );
  490. jpegInfo.err = jpeg_std_error(&jerr.m_Base);
  491. jpegInfo.err->error_exit = &ValveJpegErrorHandler;
  492. // create the decompress struct.
  493. jpeg_create_decompress(&jpegInfo);
  494. if ( setjmp( jerr.m_ErrorContext ) )
  495. {
  496. // Get here if there is any error
  497. jpeg_destroy_decompress( &jpegInfo );
  498. fclose( infile );
  499. //g_pFullFileSystem->Close( fileHandle );
  500. errcode = CE_ERROR_PARSING_SOURCE;
  501. return NULL;
  502. }
  503. jpeg_stdio_src(&jpegInfo, infile);
  504. //jpegInfo.src = &src;
  505. // read in the jpeg header and make sure that's all good.
  506. if (jpeg_read_header(&jpegInfo, TRUE) != JPEG_HEADER_OK)
  507. {
  508. fclose( infile );
  509. //g_pFullFileSystem->Close( fileHandle );
  510. errcode = CE_ERROR_PARSING_SOURCE;
  511. return NULL;
  512. }
  513. // start the decompress with the jpeg engine.
  514. if ( !jpeg_start_decompress(&jpegInfo) )
  515. {
  516. jpeg_destroy_decompress(&jpegInfo);
  517. fclose( infile );
  518. //g_pFullFileSystem->Close( fileHandle );
  519. errcode = CE_ERROR_PARSING_SOURCE;
  520. return NULL;
  521. }
  522. // We only support 24-bit JPEG's
  523. if ( jpegInfo.out_color_space != JCS_RGB || jpegInfo.output_components != 3 )
  524. {
  525. jpeg_destroy_decompress(&jpegInfo);
  526. fclose( infile );
  527. //g_pFullFileSystem->Close( fileHandle );
  528. errcode = CE_SOURCE_FILE_SIZE_NOT_SUPPORTED;
  529. return NULL;
  530. }
  531. // now that we've started the decompress with the jpeg lib, we have the attributes of the
  532. // image ready to be read out of the decompress struct.
  533. row_stride = jpegInfo.output_width * 4;
  534. image_height = jpegInfo.image_height;
  535. image_width = jpegInfo.image_width;
  536. int mem_required = jpegInfo.image_height * row_stride;
  537. // allocate the memory to read the image data into.
  538. unsigned char *buf = (unsigned char *)malloc(mem_required);
  539. if (buf == NULL)
  540. {
  541. jpeg_destroy_decompress(&jpegInfo);
  542. fclose( infile );
  543. //g_pFullFileSystem->Close( fileHandle );
  544. errcode = CE_MEMORY_ERROR;
  545. return NULL;
  546. }
  547. // read in all the scan lines of the image into our image data buffer.
  548. bool working = true;
  549. while (working && (jpegInfo.output_scanline < jpegInfo.output_height))
  550. {
  551. unsigned char *pRow = &(buf[cur_row * row_stride]);
  552. row_pointer[0] = pRow;
  553. if ( !jpeg_read_scanlines(&jpegInfo, row_pointer, 1) )
  554. {
  555. working = false;
  556. }
  557. // Expand the row RGB -> RGBA
  558. for ( int x = image_width-1 ; x >= 0 ; --x )
  559. {
  560. pRow[x*4+3] = 0xff;
  561. pRow[x*4+2] = pRow[x*3+2];
  562. pRow[x*4+1] = pRow[x*3+1];
  563. pRow[x*4] = pRow[x*3];
  564. }
  565. ++cur_row;
  566. }
  567. // Clean up
  568. fclose( infile );
  569. //g_pFullFileSystem->Close( fileHandle );
  570. jpeg_destroy_decompress(&jpegInfo);
  571. // Check success status
  572. if (!working)
  573. {
  574. free(buf);
  575. errcode = CE_ERROR_PARSING_SOURCE;
  576. return NULL;
  577. }
  578. // OK!
  579. width = image_width;
  580. height = image_height;
  581. errcode = CE_SUCCESS;
  582. return buf;
  583. #else
  584. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  585. return NULL;
  586. #endif
  587. }
  588. ConversionErrorType ImgUtl_ReadJPEGAsRGBA( CUtlBuffer &srcBuf, CUtlBuffer &dstBuf, int &width, int &height )
  589. {
  590. #if !defined( _X360 )
  591. // Point directly to our CUtlBuffer data
  592. CJpegSourceMgr jpgMgr;
  593. jpgMgr.bytes_in_buffer = srcBuf.Size();
  594. jpgMgr.next_input_byte = (unsigned char*) srcBuf.Base();
  595. // Load the jpeg
  596. struct jpeg_decompress_struct jpegInfo;
  597. struct ValveJpegErrorHandler_t jerr;
  598. memset( &jpegInfo, 0, sizeof( jpegInfo ) );
  599. jpegInfo.err = jpeg_std_error(&jerr.m_Base);
  600. jpegInfo.err->error_exit = &ValveJpegErrorHandler;
  601. // create the decompress struct.
  602. jpeg_create_decompress(&jpegInfo);
  603. if ( setjmp( jerr.m_ErrorContext ) )
  604. {
  605. // Get here if there is any error
  606. jpeg_destroy_decompress( &jpegInfo );
  607. return CE_ERROR_PARSING_SOURCE;
  608. }
  609. // Set our source
  610. jpegInfo.src = &jpgMgr;
  611. // read in the jpeg header and make sure that's all good.
  612. if (jpeg_read_header(&jpegInfo, TRUE) != JPEG_HEADER_OK)
  613. {
  614. //fclose( infile );
  615. //g_pFullFileSystem->Close( fileHandle );
  616. return CE_ERROR_PARSING_SOURCE;
  617. }
  618. // start the decompress with the jpeg engine.
  619. if ( !jpeg_start_decompress(&jpegInfo) )
  620. {
  621. jpeg_destroy_decompress(&jpegInfo);
  622. return CE_ERROR_PARSING_SOURCE;
  623. }
  624. // We only support 24-bit JPEG's
  625. if ( jpegInfo.out_color_space != JCS_RGB || jpegInfo.output_components != 3 )
  626. {
  627. jpeg_destroy_decompress(&jpegInfo);
  628. return CE_SOURCE_FILE_SIZE_NOT_SUPPORTED;
  629. }
  630. // now that we've started the decompress with the jpeg lib, we have the attributes of the
  631. // image ready to be read out of the decompress struct.
  632. JSAMPROW row_pointer[1];
  633. int row_stride;
  634. int cur_row = 0;
  635. // image attributes
  636. int image_height;
  637. int image_width;
  638. row_stride = jpegInfo.output_width * 4;
  639. image_height = jpegInfo.image_height;
  640. image_width = jpegInfo.image_width;
  641. int mem_required = jpegInfo.image_height * row_stride;
  642. // Alloc a temporary buffer to serialize to
  643. dstBuf.EnsureCapacity( mem_required );
  644. unsigned char *pDstBuf = (unsigned char *) dstBuf.PeekPut();
  645. // read in all the scan lines of the image into our image data buffer.
  646. bool working = true;
  647. while (working && (jpegInfo.output_scanline < jpegInfo.output_height))
  648. {
  649. unsigned char *pRow = &(pDstBuf[cur_row * row_stride]);
  650. row_pointer[0] = pRow;
  651. if ( !jpeg_read_scanlines(&jpegInfo, row_pointer, 1) )
  652. {
  653. working = false;
  654. }
  655. // Expand the row RGB -> RGBA
  656. for ( int x = image_width-1 ; x >= 0 ; --x )
  657. {
  658. pRow[x*4+3] = 0xff;
  659. pRow[x*4+2] = pRow[x*3+2];
  660. pRow[x*4+1] = pRow[x*3+1];
  661. pRow[x*4] = pRow[x*3];
  662. }
  663. ++cur_row;
  664. }
  665. // Clean up
  666. //fclose( infile );
  667. //g_pFullFileSystem->Close( fileHandle );
  668. jpeg_destroy_decompress(&jpegInfo);
  669. // Check success status
  670. if ( !working )
  671. {
  672. dstBuf.Purge();
  673. return CE_ERROR_PARSING_SOURCE;
  674. }
  675. // Place our read point at the end of the file
  676. dstBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, mem_required );
  677. // OK!
  678. width = image_width;
  679. height = image_height;
  680. return CE_SUCCESS;
  681. #else
  682. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  683. return NULL;
  684. #endif
  685. }
  686. static void ReadPNGData( png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead )
  687. {
  688. // Cast pointer
  689. CUtlBuffer *pBuf = (CUtlBuffer *)png_get_io_ptr( png_ptr );
  690. Assert( pBuf );
  691. // Check for IO error
  692. if ( pBuf->TellGet() + (int)byteCountToRead > pBuf->TellPut() )
  693. {
  694. // Attempt to read past the end of the buffer.
  695. // Use longjmp to report the error
  696. png_longjmp( png_ptr, 1 );
  697. }
  698. // Read the bytes
  699. pBuf->Get( outBytes, byteCountToRead );
  700. }
  701. unsigned char *ImgUtl_ReadPNGAsRGBA( const char *pngPath, int &width, int &height, ConversionErrorType &errcode )
  702. {
  703. #if !defined( _X360 )
  704. // Just load the whole file into a memory buffer
  705. CUtlBuffer bufFileContents;
  706. if ( !g_pFullFileSystem->ReadFile( pngPath, NULL, bufFileContents ) )
  707. {
  708. errcode = CE_CANT_OPEN_SOURCE_FILE;
  709. return NULL;
  710. }
  711. // Load it
  712. return ImgUtl_ReadPNGAsRGBAFromBuffer( bufFileContents, width, height, errcode );
  713. #else
  714. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  715. return NULL;
  716. #endif
  717. }
  718. unsigned char *ImgUtl_ReadPNGAsRGBAFromBuffer( CUtlBuffer &buffer, int &width, int &height, ConversionErrorType &errcode )
  719. {
  720. #if !defined( _X360 ) && defined( WIN32 )
  721. png_const_bytep pngData = (png_const_bytep)buffer.Base();
  722. if (png_sig_cmp( pngData, 0, 8))
  723. {
  724. errcode = CE_ERROR_PARSING_SOURCE;
  725. return NULL;
  726. }
  727. png_structp png_ptr = NULL;
  728. png_infop info_ptr = NULL;
  729. /* could pass pointers to user-defined error handlers instead of NULLs: */
  730. png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
  731. if (!png_ptr)
  732. {
  733. errcode = CE_MEMORY_ERROR;
  734. return NULL;
  735. }
  736. unsigned char *pResultData = NULL;
  737. png_bytepp row_pointers = NULL;
  738. info_ptr = png_create_info_struct( png_ptr );
  739. if ( !info_ptr )
  740. {
  741. errcode = CE_MEMORY_ERROR;
  742. fail:
  743. png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
  744. if ( row_pointers )
  745. {
  746. free( row_pointers );
  747. }
  748. if ( pResultData )
  749. {
  750. free( pResultData );
  751. }
  752. return NULL;
  753. }
  754. /* setjmp() must be called in every function that calls a PNG-reading
  755. * libpng function */
  756. if ( setjmp( png_ptr->png_jmpbuf) )
  757. {
  758. errcode = CE_ERROR_PARSING_SOURCE;
  759. goto fail;
  760. }
  761. png_set_read_fn( png_ptr, &buffer, ReadPNGData );
  762. png_read_info( png_ptr, info_ptr ); /* read all PNG info up to image data */
  763. /* alternatively, could make separate calls to png_get_image_width(),
  764. * etc., but want bit_depth and color_type for later [don't care about
  765. * compression_type and filter_type => NULLs] */
  766. int bit_depth;
  767. int color_type;
  768. uint32 png_width;
  769. uint32 png_height;
  770. png_get_IHDR( png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type, NULL, NULL, NULL );
  771. width = png_width;
  772. height = png_height;
  773. png_uint_32 rowbytes;
  774. /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
  775. * transparency chunks to full alpha channel; strip 16-bit-per-sample
  776. * images to 8 bits per sample; and convert grayscale to RGB[A] */
  777. if (color_type == PNG_COLOR_TYPE_PALETTE)
  778. png_set_expand( png_ptr );
  779. if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
  780. png_set_expand( png_ptr );
  781. if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
  782. png_set_expand( png_ptr );
  783. if (bit_depth == 16)
  784. png_set_strip_16( png_ptr );
  785. if (color_type == PNG_COLOR_TYPE_GRAY ||
  786. color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  787. png_set_gray_to_rgb( png_ptr );
  788. // Force in an alpha channel
  789. if ( !( color_type & PNG_COLOR_MASK_ALPHA ) )
  790. {
  791. png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
  792. }
  793. /*
  794. double gamma;
  795. if (png_get_gAMA(png_ptr, info_ptr, &gamma))
  796. png_set_gamma(png_ptr, display_exponent, gamma);
  797. */
  798. /* all transformations have been registered; now update info_ptr data,
  799. * get rowbytes and channels, and allocate image memory */
  800. png_read_update_info( png_ptr, info_ptr );
  801. rowbytes = png_get_rowbytes( png_ptr, info_ptr );
  802. png_byte channels = (int)png_get_channels( png_ptr, info_ptr );
  803. if ( channels != 4 )
  804. {
  805. Assert( channels == 4 );
  806. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  807. goto fail;
  808. }
  809. row_pointers = (png_bytepp)malloc( height*sizeof(png_bytep) );
  810. pResultData = (unsigned char *)malloc( rowbytes*height );
  811. if ( row_pointers == NULL || pResultData == NULL )
  812. {
  813. errcode = CE_MEMORY_ERROR;
  814. goto fail;
  815. }
  816. /* set the individual row_pointers to point at the correct offsets */
  817. for ( int i = 0; i < height; ++i)
  818. row_pointers[i] = pResultData + i*rowbytes;
  819. /* now we can go ahead and just read the whole image */
  820. png_read_image( png_ptr, row_pointers );
  821. png_read_end(png_ptr, NULL);
  822. free( row_pointers );
  823. row_pointers = NULL;
  824. // Clean up
  825. png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
  826. // OK!
  827. width = png_width;
  828. height = png_height;
  829. errcode = CE_SUCCESS;
  830. return pResultData;
  831. #else
  832. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  833. return NULL;
  834. #endif
  835. }
  836. unsigned char *ImgUtl_ReadBMPAsRGBA( const char *bmpPath, int &width, int &height, ConversionErrorType &errcode )
  837. {
  838. #ifdef WIN32
  839. // Load up bitmap
  840. HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, bmpPath, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_DEFAULTSIZE);
  841. // Handle failure
  842. if ( hBitmap == NULL)
  843. {
  844. // !KLUDGE! Try to detect what went wrong
  845. FILE *fp = fopen( bmpPath, "rb" );
  846. if (fp == NULL)
  847. {
  848. errcode = CE_CANT_OPEN_SOURCE_FILE;
  849. }
  850. else
  851. {
  852. errcode = CE_ERROR_PARSING_SOURCE;
  853. }
  854. return NULL;
  855. }
  856. BITMAP bitmap;
  857. GetObject(hBitmap, sizeof(bitmap), &bitmap);
  858. BITMAPINFO *bitmapInfo;
  859. bool bUseColorTable = false;
  860. if (bitmap.bmBitsPixel == 24 || bitmap.bmBitsPixel == 32)
  861. {
  862. bitmapInfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO));
  863. }
  864. else if (bitmap.bmBitsPixel == 8 || bitmap.bmBitsPixel == 4 || bitmap.bmBitsPixel == 1)
  865. {
  866. int colorsUsed = 1 << bitmap.bmBitsPixel;
  867. bitmapInfo = (BITMAPINFO *)malloc(colorsUsed * sizeof(RGBQUAD) + sizeof(BITMAPINFO));
  868. bUseColorTable = true;
  869. }
  870. else
  871. {
  872. DeleteObject(hBitmap);
  873. errcode = CE_SOURCE_FILE_BMP_FORMAT_NOT_SUPPORTED;
  874. return NULL;
  875. }
  876. memset(bitmapInfo, 0, sizeof(BITMAPINFO));
  877. bitmapInfo->bmiHeader.biSize = sizeof(bitmapInfo->bmiHeader);
  878. if (bUseColorTable)
  879. {
  880. bitmapInfo->bmiHeader.biBitCount = bitmap.bmBitsPixel; // need to specify the bits per pixel so GDI will generate a color table for us.
  881. }
  882. HDC dc = CreateCompatibleDC(NULL);
  883. int retcode = GetDIBits(dc, hBitmap, 0, bitmap.bmHeight, NULL, bitmapInfo, DIB_RGB_COLORS);
  884. DeleteDC(dc);
  885. if (retcode == 0)
  886. {
  887. // error getting the bitmap info for some reason.
  888. free(bitmapInfo);
  889. errcode = CE_SOURCE_FILE_BMP_FORMAT_NOT_SUPPORTED;
  890. return NULL;
  891. }
  892. int nDestStride = 4 * bitmap.bmWidth;
  893. int mem_required = nDestStride * bitmap.bmHeight; // mem required for copying the data out into RGBA format.
  894. unsigned char *buf = (unsigned char *)malloc(mem_required);
  895. if (buf == NULL)
  896. {
  897. free(bitmapInfo);
  898. errcode = CE_MEMORY_ERROR;
  899. return NULL;
  900. }
  901. if (bitmapInfo->bmiHeader.biBitCount == 32)
  902. {
  903. for (int y = 0; y < bitmap.bmHeight; ++y)
  904. {
  905. unsigned char *pDest = buf + nDestStride * ( ( bitmap.bmHeight - 1 ) - y ); // BMPs are stored upside down
  906. const unsigned char *pSrc = (unsigned char *)(bitmap.bmBits) + (y * bitmap.bmWidthBytes);
  907. for (int x = 0; x < bitmap.bmWidth; ++x)
  908. {
  909. // Swap BGR -> RGB while copying data
  910. pDest[0] = pSrc[2]; // R
  911. pDest[1] = pSrc[1]; // G
  912. pDest[2] = pSrc[0]; // B
  913. pDest[3] = pSrc[3]; // A
  914. pSrc += 4;
  915. pDest += 4;
  916. }
  917. }
  918. }
  919. else if (bitmapInfo->bmiHeader.biBitCount == 24)
  920. {
  921. for (int y = 0; y < bitmap.bmHeight; ++y)
  922. {
  923. unsigned char *pDest = buf + nDestStride * ( ( bitmap.bmHeight - 1 ) - y ); // BMPs are stored upside down
  924. const unsigned char *pSrc = (unsigned char *)(bitmap.bmBits) + (y * bitmap.bmWidthBytes);
  925. for (int x = 0; x < bitmap.bmWidth; ++x)
  926. {
  927. // Swap BGR -> RGB while copying data
  928. pDest[0] = pSrc[2]; // R
  929. pDest[1] = pSrc[1]; // G
  930. pDest[2] = pSrc[0]; // B
  931. pDest[3] = 0xff; // A
  932. pSrc += 3;
  933. pDest += 4;
  934. }
  935. }
  936. }
  937. else if (bitmapInfo->bmiHeader.biBitCount == 8)
  938. {
  939. // 8-bit 256 color bitmap.
  940. for (int y = 0; y < bitmap.bmHeight; ++y)
  941. {
  942. unsigned char *pDest = buf + nDestStride * ( ( bitmap.bmHeight - 1 ) - y ); // BMPs are stored upside down
  943. const unsigned char *pSrc = (unsigned char *)(bitmap.bmBits) + (y * bitmap.bmWidthBytes);
  944. for (int x = 0; x < bitmap.bmWidth; ++x)
  945. {
  946. // compute the color map entry for this pixel
  947. int colorTableEntry = *pSrc;
  948. // get the color for this color map entry.
  949. RGBQUAD *rgbQuad = &(bitmapInfo->bmiColors[colorTableEntry]);
  950. // copy the color values for this pixel to the destination buffer.
  951. pDest[0] = rgbQuad->rgbRed;
  952. pDest[1] = rgbQuad->rgbGreen;
  953. pDest[2] = rgbQuad->rgbBlue;
  954. pDest[3] = 0xff;
  955. ++pSrc;
  956. pDest += 4;
  957. }
  958. }
  959. }
  960. else if (bitmapInfo->bmiHeader.biBitCount == 4)
  961. {
  962. // 4-bit 16 color bitmap.
  963. for (int y = 0; y < bitmap.bmHeight; ++y)
  964. {
  965. unsigned char *pDest = buf + nDestStride * ( ( bitmap.bmHeight - 1 ) - y ); // BMPs are stored upside down
  966. const unsigned char *pSrc = (unsigned char *)(bitmap.bmBits) + (y * bitmap.bmWidthBytes);
  967. // Two pixels at a time
  968. for (int x = 0; x < bitmap.bmWidth; x += 2)
  969. {
  970. // get the color table entry for this pixel
  971. int colorTableEntry = (0xf0 & *pSrc) >> 4;
  972. // get the color values for this pixel's color table entry.
  973. RGBQUAD *rgbQuad = &(bitmapInfo->bmiColors[colorTableEntry]);
  974. // copy the pixel's color values to the destination buffer.
  975. pDest[0] = pSrc[2]; // R
  976. pDest[1] = pSrc[1]; // G
  977. pDest[2] = pSrc[0]; // B
  978. pDest[3] = 0xff; // A
  979. // make sure we haven't reached the end of the row.
  980. if ((x + 1) > bitmap.bmWidth)
  981. {
  982. break;
  983. }
  984. pDest += 4;
  985. // get the color table entry for this pixel.
  986. colorTableEntry = 0x0f & *pSrc;
  987. // get the color values for this pixel's color table entry.
  988. rgbQuad = &(bitmapInfo->bmiColors[colorTableEntry]);
  989. // copy the pixel's color values to the destination buffer.
  990. pDest[0] = pSrc[2]; // R
  991. pDest[1] = pSrc[1]; // G
  992. pDest[2] = pSrc[0]; // B
  993. pDest[3] = 0xff; // A
  994. ++pSrc;
  995. pDest += 4;
  996. }
  997. }
  998. }
  999. else if (bitmapInfo->bmiHeader.biBitCount == 1)
  1000. {
  1001. // 1-bit monochrome bitmap.
  1002. for (int y = 0; y < bitmap.bmHeight; ++y)
  1003. {
  1004. unsigned char *pDest = buf + nDestStride * ( ( bitmap.bmHeight - 1 ) - y ); // BMPs are stored upside down
  1005. const unsigned char *pSrc = (unsigned char *)(bitmap.bmBits) + (y * bitmap.bmWidthBytes);
  1006. // Eight pixels at a time
  1007. int x = 0;
  1008. while (x < bitmap.bmWidth)
  1009. {
  1010. RGBQUAD *rgbQuad = NULL;
  1011. int bitMask = 0x80;
  1012. // go through all 8 bits in this byte to get all 8 pixel colors.
  1013. do
  1014. {
  1015. // get the value of the bit for this pixel.
  1016. int bit = *pSrc & bitMask;
  1017. // bit will either be 0 or non-zero since there are only two colors.
  1018. if (bit == 0)
  1019. {
  1020. rgbQuad = &(bitmapInfo->bmiColors[0]);
  1021. }
  1022. else
  1023. {
  1024. rgbQuad = &(bitmapInfo->bmiColors[1]);
  1025. }
  1026. // copy this pixel's color values into the destination buffer.
  1027. pDest[0] = pSrc[2]; // R
  1028. pDest[1] = pSrc[1]; // G
  1029. pDest[2] = pSrc[0]; // B
  1030. pDest[3] = 0xff; // A
  1031. pDest += 4;
  1032. // go to the next pixel.
  1033. ++x;
  1034. bitMask = bitMask >> 1;
  1035. } while ((x < bitmap.bmWidth) && (bitMask > 0));
  1036. ++pSrc;
  1037. }
  1038. }
  1039. }
  1040. else
  1041. {
  1042. free(bitmapInfo);
  1043. free(buf);
  1044. DeleteObject(hBitmap);
  1045. errcode = CE_SOURCE_FILE_BMP_FORMAT_NOT_SUPPORTED;
  1046. return NULL;
  1047. }
  1048. free(bitmapInfo);
  1049. DeleteObject(hBitmap);
  1050. // OK!
  1051. width = bitmap.bmWidth;
  1052. height = bitmap.bmHeight;
  1053. errcode = CE_SUCCESS;
  1054. return buf;
  1055. #else
  1056. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1057. return NULL;
  1058. #endif
  1059. }
  1060. unsigned char *ImgUtl_ReadImageAsRGBA( const char *path, int &width, int &height, ConversionErrorType &errcode )
  1061. {
  1062. // Split out the file extension
  1063. const char *pExt = V_GetFileExtension( path );
  1064. if ( pExt )
  1065. {
  1066. if ( !Q_stricmp(pExt, "vtf") )
  1067. {
  1068. return ImgUtl_ReadVTFAsRGBA( path, width, height, errcode );
  1069. }
  1070. if ( !Q_stricmp(pExt, "bmp") )
  1071. {
  1072. return ImgUtl_ReadBMPAsRGBA( path, width, height, errcode );
  1073. }
  1074. if ( !Q_stricmp(pExt, "jpg") || !Q_stricmp(pExt, "jpeg") )
  1075. {
  1076. return ImgUtl_ReadJPEGAsRGBA( path, width, height, errcode );
  1077. }
  1078. if ( !Q_stricmp(pExt, "png") )
  1079. {
  1080. return ImgUtl_ReadPNGAsRGBA( path, width, height, errcode );
  1081. }
  1082. if ( !Q_stricmp(pExt, "tga") )
  1083. {
  1084. TGAHeader header;
  1085. return ImgUtl_ReadTGAAsRGBA( path, width, height, errcode, header );
  1086. }
  1087. }
  1088. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1089. return NULL;
  1090. }
  1091. // resizes the file specified by tgaPath so that it has dimensions that are
  1092. // powers-of-two and is equal to or smaller than (nMaxWidth)x(nMaxHeight).
  1093. // also converts from 24-bit RGB to 32-bit RGB (with 8-bit alpha)
  1094. ConversionErrorType ImgUtl_ConvertTGA(const char *tgaPath, int nMaxWidth/*=-1*/, int nMaxHeight/*=-1*/)
  1095. {
  1096. int tgaWidth = 0, tgaHeight = 0;
  1097. ConversionErrorType errcode;
  1098. TGAHeader tgaHeader;
  1099. unsigned char *srcBuffer = ImgUtl_ReadTGAAsRGBA(tgaPath, tgaWidth, tgaHeight, errcode, tgaHeader);
  1100. if (srcBuffer == NULL)
  1101. {
  1102. return errcode;
  1103. }
  1104. int paddedImageWidth, paddedImageHeight;
  1105. if ((tgaWidth <= 0) || (tgaHeight <= 0))
  1106. {
  1107. free(srcBuffer);
  1108. return CE_ERROR_PARSING_SOURCE;
  1109. }
  1110. // get the nearest power of two that is greater than the width of the image.
  1111. paddedImageWidth = tgaWidth;
  1112. if (!IsPowerOfTwo(paddedImageWidth))
  1113. {
  1114. // width is not a power of two, calculate the next highest power of two value.
  1115. int i = 1;
  1116. while (paddedImageWidth > 1)
  1117. {
  1118. paddedImageWidth = paddedImageWidth >> 1;
  1119. ++i;
  1120. }
  1121. paddedImageWidth = paddedImageWidth << i;
  1122. }
  1123. // make sure the width is less than or equal to nMaxWidth
  1124. if (nMaxWidth != -1 && paddedImageWidth > nMaxWidth)
  1125. {
  1126. paddedImageWidth = nMaxWidth;
  1127. }
  1128. // get the nearest power of two that is greater than the height of the image
  1129. paddedImageHeight = tgaHeight;
  1130. if (!IsPowerOfTwo(paddedImageHeight))
  1131. {
  1132. // height is not a power of two, calculate the next highest power of two value.
  1133. int i = 1;
  1134. while (paddedImageHeight > 1)
  1135. {
  1136. paddedImageHeight = paddedImageHeight >> 1;
  1137. ++i;
  1138. }
  1139. paddedImageHeight = paddedImageHeight << i;
  1140. }
  1141. // make sure the height is less than or equal to nMaxHeight
  1142. if (nMaxHeight != -1 && paddedImageHeight > nMaxHeight)
  1143. {
  1144. paddedImageHeight = nMaxHeight;
  1145. }
  1146. // compute the amount of stretching that needs to be done to both width and height to get the image to fit.
  1147. float widthRatio = (float)paddedImageWidth / tgaWidth;
  1148. float heightRatio = (float)paddedImageHeight / tgaHeight;
  1149. int finalWidth;
  1150. int finalHeight;
  1151. // compute the final dimensions of the stretched image.
  1152. if (widthRatio < heightRatio)
  1153. {
  1154. finalWidth = paddedImageWidth;
  1155. finalHeight = (int)(tgaHeight * widthRatio + 0.5f);
  1156. // i.e. for 1x1 size pixels in the resized image we will take color from sourceRatio x sourceRatio sized pixels in the source image.
  1157. }
  1158. else if (heightRatio < widthRatio)
  1159. {
  1160. finalHeight = paddedImageHeight;
  1161. finalWidth = (int)(tgaWidth * heightRatio + 0.5f);
  1162. }
  1163. else
  1164. {
  1165. finalHeight = paddedImageHeight;
  1166. finalWidth = paddedImageWidth;
  1167. }
  1168. unsigned char *resizeBuffer = (unsigned char *)malloc(finalWidth * finalHeight * 4);
  1169. // do the actual stretching
  1170. ImgUtl_StretchRGBAImage(srcBuffer, tgaWidth, tgaHeight, resizeBuffer, finalWidth, finalHeight);
  1171. free(srcBuffer); // don't need this anymore.
  1172. ///////////////////////////////////////////////////////////////////////
  1173. ///// need to pad the image so both dimensions are power of two's /////
  1174. ///////////////////////////////////////////////////////////////////////
  1175. unsigned char *finalBuffer = (unsigned char *)malloc(paddedImageWidth * paddedImageHeight * 4);
  1176. ImgUtl_PadRGBAImage(resizeBuffer, finalWidth, finalHeight, finalBuffer, paddedImageWidth, paddedImageHeight);
  1177. FILE *outfile = fopen(tgaPath, "wb");
  1178. if (outfile == NULL)
  1179. {
  1180. free(resizeBuffer);
  1181. free(finalBuffer);
  1182. return CE_ERROR_WRITING_OUTPUT_FILE;
  1183. }
  1184. tgaHeader.width = paddedImageWidth;
  1185. tgaHeader.height = paddedImageHeight;
  1186. WriteTGAHeader(outfile, tgaHeader);
  1187. // Write the image data --- remember that TGA uses BGRA data
  1188. int numPixels = paddedImageWidth * paddedImageHeight;
  1189. for (int i = 0 ; i < numPixels ; ++i )
  1190. {
  1191. fputc( finalBuffer[i*4 + 2], outfile ); // B
  1192. fputc( finalBuffer[i*4 + 1], outfile ); // G
  1193. fputc( finalBuffer[i*4 ], outfile ); // R
  1194. fputc( finalBuffer[i*4 + 3], outfile ); // A
  1195. }
  1196. fclose(outfile);
  1197. free(resizeBuffer);
  1198. free(finalBuffer);
  1199. return CE_SUCCESS;
  1200. }
  1201. // resize by stretching (or compressing) an RGBA image pointed to by srcBuf into the buffer pointed to by destBuf.
  1202. // the buffers are assumed to be sized appropriately to accomidate RGBA images of the given widths and heights.
  1203. ConversionErrorType ImgUtl_StretchRGBAImage(const unsigned char *srcBuf, const int srcWidth, const int srcHeight,
  1204. unsigned char *destBuf, const int destWidth, const int destHeight)
  1205. {
  1206. if ((srcBuf == NULL) || (destBuf == NULL))
  1207. {
  1208. return CE_CANT_OPEN_SOURCE_FILE;
  1209. }
  1210. int destRow,destColumn;
  1211. float ratioX = (float)srcWidth / (float)destWidth;
  1212. float ratioY = (float)srcHeight / (float)destHeight;
  1213. // loop through all the pixels in the destination image.
  1214. for (destRow = 0; destRow < destHeight; ++destRow)
  1215. {
  1216. for (destColumn = 0; destColumn < destWidth; ++destColumn)
  1217. {
  1218. // calculate the center of the pixel in the source image.
  1219. float srcCenterX = ratioX * (destColumn + 0.5f);
  1220. float srcCenterY = ratioY * (destRow + 0.5f);
  1221. // calculate the starting and ending coords for this destination pixel in the source image.
  1222. float srcStartX = srcCenterX - (ratioX / 2.0f);
  1223. if (srcStartX < 0.0f)
  1224. {
  1225. srcStartX = 0.0f; // this should never happen, but just in case.
  1226. }
  1227. float srcStartY = srcCenterY - (ratioY / 2.0f);
  1228. if (srcStartY < 0.0f)
  1229. {
  1230. srcStartY = 0.0f; // this should never happen, but just in case.
  1231. }
  1232. float srcEndX = srcCenterX + (ratioX / 2.0f);
  1233. if (srcEndX > srcWidth)
  1234. {
  1235. srcEndX = srcWidth; // this should never happen, but just in case.
  1236. }
  1237. float srcEndY = srcCenterY + (ratioY / 2.0f);
  1238. if (srcEndY > srcHeight)
  1239. {
  1240. srcEndY = srcHeight; // this should never happen, but just in case.
  1241. }
  1242. // Calculate the percentage of each source pixels' contribution to the destination pixel color.
  1243. float srcCurrentX; // initialized at the start of the y loop.
  1244. float srcCurrentY = srcStartY;
  1245. float destRed = 0.0f;
  1246. float destGreen = 0.0f;
  1247. float destBlue = 0.0f;
  1248. float destAlpha = 0.0f;
  1249. //// loop for the parts of the source image that will contribute color to the destination pixel.
  1250. while (srcCurrentY < srcEndY)
  1251. {
  1252. float srcCurrentEndY = (float)((int)srcCurrentY + 1);
  1253. if (srcCurrentEndY > srcEndY)
  1254. {
  1255. srcCurrentEndY = srcEndY;
  1256. }
  1257. float srcCurrentHeight = srcCurrentEndY - srcCurrentY;
  1258. srcCurrentX = srcStartX;
  1259. while (srcCurrentX < srcEndX)
  1260. {
  1261. float srcCurrentEndX = (float)((int)srcCurrentX + 1);
  1262. if (srcCurrentEndX > srcEndX)
  1263. {
  1264. srcCurrentEndX = srcEndX;
  1265. }
  1266. float srcCurrentWidth = srcCurrentEndX - srcCurrentX;
  1267. // compute the percentage of the destination pixel's color this source pixel will contribute.
  1268. float srcColorPercentage = (srcCurrentWidth / ratioX) * (srcCurrentHeight / ratioY);
  1269. int srcCurrentPixelX = (int)srcCurrentX;
  1270. int srcCurrentPixelY = (int)srcCurrentY;
  1271. // get the color values for this source pixel.
  1272. unsigned char srcCurrentRed = srcBuf[(srcCurrentPixelY * srcWidth * 4) + (srcCurrentPixelX * 4)];
  1273. unsigned char srcCurrentGreen = srcBuf[(srcCurrentPixelY * srcWidth * 4) + (srcCurrentPixelX * 4) + 1];
  1274. unsigned char srcCurrentBlue = srcBuf[(srcCurrentPixelY * srcWidth * 4) + (srcCurrentPixelX * 4) + 2];
  1275. unsigned char srcCurrentAlpha = srcBuf[(srcCurrentPixelY * srcWidth * 4) + (srcCurrentPixelX * 4) + 3];
  1276. // add the color contribution from this source pixel to the destination pixel.
  1277. destRed += srcCurrentRed * srcColorPercentage;
  1278. destGreen += srcCurrentGreen * srcColorPercentage;
  1279. destBlue += srcCurrentBlue * srcColorPercentage;
  1280. destAlpha += srcCurrentAlpha * srcColorPercentage;
  1281. srcCurrentX = srcCurrentEndX;
  1282. }
  1283. srcCurrentY = srcCurrentEndY;
  1284. }
  1285. // assign the computed color to the destination pixel, round to the nearest value. Make sure the value doesn't exceed 255.
  1286. destBuf[(destRow * destWidth * 4) + (destColumn * 4)] = MIN((int)(destRed + 0.5f), 255);
  1287. destBuf[(destRow * destWidth * 4) + (destColumn * 4) + 1] = MIN((int)(destGreen + 0.5f), 255);
  1288. destBuf[(destRow * destWidth * 4) + (destColumn * 4) + 2] = MIN((int)(destBlue + 0.5f), 255);
  1289. destBuf[(destRow * destWidth * 4) + (destColumn * 4) + 3] = MIN((int)(destAlpha + 0.5f), 255);
  1290. } // column loop
  1291. } // row loop
  1292. return CE_SUCCESS;
  1293. }
  1294. ConversionErrorType ImgUtl_PadRGBAImage(const unsigned char *srcBuf, const int srcWidth, const int srcHeight,
  1295. unsigned char *destBuf, const int destWidth, const int destHeight)
  1296. {
  1297. if ((srcBuf == NULL) || (destBuf == NULL))
  1298. {
  1299. return CE_CANT_OPEN_SOURCE_FILE;
  1300. }
  1301. memset(destBuf, 0, destWidth * destHeight * 4);
  1302. if ((destWidth < srcWidth) || (destHeight < srcHeight))
  1303. {
  1304. return CE_ERROR_PARSING_SOURCE;
  1305. }
  1306. if ((srcWidth == destWidth) && (srcHeight == destHeight))
  1307. {
  1308. // no padding is needed, just copy the buffer straight over and call it done.
  1309. memcpy(destBuf, srcBuf, destWidth * destHeight * 4);
  1310. return CE_SUCCESS;
  1311. }
  1312. if (destWidth == srcWidth)
  1313. {
  1314. // only the top and bottom of the image need padding.
  1315. // do this separately since we can do this more efficiently than the other cases.
  1316. int numRowsToPad = (destHeight - srcHeight) / 2;
  1317. memcpy(destBuf + (numRowsToPad * destWidth * 4), srcBuf, srcWidth * srcHeight * 4);
  1318. }
  1319. else
  1320. {
  1321. int numColumnsToPad = (destWidth - srcWidth) / 2;
  1322. int numRowsToPad = (destHeight - srcHeight) / 2;
  1323. int lastRow = numRowsToPad + srcHeight;
  1324. int row;
  1325. for (row = numRowsToPad; row < lastRow; ++row)
  1326. {
  1327. unsigned char * destOffset = destBuf + (row * destWidth * 4) + (numColumnsToPad * 4);
  1328. const unsigned char * srcOffset = srcBuf + ((row - numRowsToPad) * srcWidth * 4);
  1329. memcpy(destOffset, srcOffset, srcWidth * 4);
  1330. }
  1331. }
  1332. return CE_SUCCESS;
  1333. }
  1334. // convert TGA file at the given location to a VTF file of the same root name at the same location.
  1335. ConversionErrorType ImgUtl_ConvertTGAToVTF(const char *tgaPath, int nMaxWidth/*=-1*/, int nMaxHeight/*=-1*/ )
  1336. {
  1337. FILE *infile = fopen(tgaPath, "rb");
  1338. if (infile == NULL)
  1339. {
  1340. return CE_CANT_OPEN_SOURCE_FILE;
  1341. }
  1342. // read out the header of the image.
  1343. TGAHeader header;
  1344. ImgUtl_ReadTGAHeader(infile, header);
  1345. // check to make sure that the TGA has the proper dimensions and size.
  1346. if (!IsPowerOfTwo(header.width) || !IsPowerOfTwo(header.height))
  1347. {
  1348. fclose(infile);
  1349. return CE_SOURCE_FILE_SIZE_NOT_SUPPORTED;
  1350. }
  1351. // check to make sure that the TGA isn't too big, if we care.
  1352. if ( ( nMaxWidth != -1 && header.width > nMaxWidth ) || ( nMaxHeight != -1 && header.height > nMaxHeight ) )
  1353. {
  1354. fclose(infile);
  1355. return CE_SOURCE_FILE_SIZE_NOT_SUPPORTED;
  1356. }
  1357. int imageMemoryFootprint = header.width * header.height * header.bits / 8;
  1358. CUtlBuffer inbuf(0, imageMemoryFootprint);
  1359. // read in the image
  1360. int nBytesRead = fread(inbuf.Base(), imageMemoryFootprint, 1, infile);
  1361. fclose(infile);
  1362. inbuf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead );
  1363. // load vtex_dll.dll and get the interface to it.
  1364. CSysModule *vtexmod = Sys_LoadModule("vtex_dll");
  1365. if (vtexmod == NULL)
  1366. {
  1367. return CE_ERROR_LOADING_DLL;
  1368. }
  1369. CreateInterfaceFn factory = Sys_GetFactory(vtexmod);
  1370. if (factory == NULL)
  1371. {
  1372. Sys_UnloadModule(vtexmod);
  1373. return CE_ERROR_LOADING_DLL;
  1374. }
  1375. IVTex *vtex = (IVTex *)factory(IVTEX_VERSION_STRING, NULL);
  1376. if (vtex == NULL)
  1377. {
  1378. Sys_UnloadModule(vtexmod);
  1379. return CE_ERROR_LOADING_DLL;
  1380. }
  1381. char *vtfParams[4];
  1382. // the 0th entry is skipped cause normally thats the program name.
  1383. vtfParams[0] = "";
  1384. vtfParams[1] = "-quiet";
  1385. vtfParams[2] = "-dontusegamedir";
  1386. vtfParams[3] = (char *)tgaPath;
  1387. // call vtex to do the conversion.
  1388. vtex->VTex(4, vtfParams);
  1389. Sys_UnloadModule(vtexmod);
  1390. return CE_SUCCESS;
  1391. }
  1392. static void DoCopyFile( const char *source, const char *destination )
  1393. {
  1394. #if defined( WIN32 )
  1395. CopyFile( source, destination, true );
  1396. #elif defined( OSX )
  1397. copyfile( source, destination, NULL, COPYFILE_ALL );
  1398. #elif defined( ENGINE_DLL )
  1399. ::COM_CopyFile( source, destination );
  1400. #elif REPLAY_DLL
  1401. g_pEngine->CopyFile( source, destination );
  1402. #else
  1403. engine->CopyLocalFile( source, destination );
  1404. #endif
  1405. }
  1406. static void DoDeleteFile( const char *filename )
  1407. {
  1408. #ifdef WIN32
  1409. DeleteFile( filename );
  1410. #else
  1411. unlink( filename );
  1412. #endif
  1413. }
  1414. ConversionErrorType ImgUtl_ConvertToVTFAndDumpVMT( const char *pInPath, const char *pMaterialsSubDir, int nMaxWidth/*=-1*/, int nMaxHeight/*=-1*/ )
  1415. {
  1416. #ifndef _XBOX
  1417. if ((pInPath == NULL) || (pInPath[0] == 0))
  1418. {
  1419. return CE_ERROR_PARSING_SOURCE;
  1420. }
  1421. ConversionErrorType nErrorCode = CE_SUCCESS;
  1422. // get the extension of the file we're to convert
  1423. char extension[MAX_PATH];
  1424. const char *constchar = pInPath + strlen(pInPath);
  1425. while ((constchar > pInPath) && (*(constchar-1) != '.'))
  1426. {
  1427. --constchar;
  1428. }
  1429. Q_strncpy(extension, constchar, MAX_PATH);
  1430. bool deleteIntermediateTGA = false;
  1431. bool deleteIntermediateVTF = false;
  1432. bool convertTGAToVTF = true;
  1433. char tgaPath[MAX_PATH*2];
  1434. char *c;
  1435. bool failed = false;
  1436. Q_strncpy(tgaPath, pInPath, sizeof(tgaPath));
  1437. // Construct a TGA version if necessary
  1438. if (stricmp(extension, "tga"))
  1439. {
  1440. c = tgaPath + strlen(tgaPath);
  1441. while ((c > tgaPath) && (*(c-1) != '\\') && (*(c-1) != '/'))
  1442. {
  1443. --c;
  1444. }
  1445. *c = 0;
  1446. char origpath[MAX_PATH*2];
  1447. Q_strncpy(origpath, tgaPath, sizeof(origpath));
  1448. int index = 0;
  1449. do {
  1450. Q_snprintf(tgaPath, sizeof(tgaPath), "%stemp%d.tga", origpath, index);
  1451. ++index;
  1452. } while (_access(tgaPath, 0) != -1);
  1453. if (!stricmp(extension, "jpg") || !stricmp(extension, "jpeg"))
  1454. {
  1455. // convert from the jpeg file format to the TGA file format
  1456. nErrorCode = ImgUtl_ConvertJPEGToTGA(pInPath, tgaPath, false);
  1457. if (nErrorCode == CE_SUCCESS)
  1458. {
  1459. deleteIntermediateTGA = true;
  1460. }
  1461. else
  1462. {
  1463. failed = true;
  1464. }
  1465. }
  1466. else if (!stricmp(extension, "bmp"))
  1467. {
  1468. // convert from the bmp file format to the TGA file format
  1469. nErrorCode = ImgUtl_ConvertBMPToTGA(pInPath, tgaPath);
  1470. if (nErrorCode == CE_SUCCESS)
  1471. {
  1472. deleteIntermediateTGA = true;
  1473. }
  1474. else
  1475. {
  1476. failed = true;
  1477. }
  1478. }
  1479. else if (!stricmp(extension, "vtf"))
  1480. {
  1481. // if the file is already in the vtf format there's no need to convert it.
  1482. convertTGAToVTF = false;
  1483. }
  1484. }
  1485. // Convert the TGA file to the VTF format if necessary
  1486. if (convertTGAToVTF && !failed)
  1487. {
  1488. nErrorCode = ImgUtl_ConvertTGA( tgaPath, nMaxWidth, nMaxHeight ); // resize TGA so that it has power-of-two dimensions with a max size of (nMaxWidth)x(nMaxHeight).
  1489. if (nErrorCode != CE_SUCCESS)
  1490. {
  1491. failed = true;
  1492. }
  1493. if (!failed)
  1494. {
  1495. char tempPath[MAX_PATH*2];
  1496. Q_strncpy(tempPath, tgaPath, sizeof(tempPath));
  1497. nErrorCode = ImgUtl_ConvertTGAToVTF( tempPath, nMaxWidth, nMaxHeight );
  1498. if (nErrorCode == CE_SUCCESS)
  1499. {
  1500. deleteIntermediateVTF = true;
  1501. }
  1502. else
  1503. {
  1504. failed = true;
  1505. }
  1506. }
  1507. }
  1508. char finalPath[MAX_PATH*2];
  1509. finalPath[0] = 0;
  1510. char vtfPath[MAX_PATH*2];
  1511. vtfPath[0] = 0;
  1512. if (!failed)
  1513. {
  1514. Q_strncpy(vtfPath, tgaPath, sizeof(vtfPath));
  1515. // rename the tga file to be a vtf file.
  1516. c = vtfPath + strlen(vtfPath);
  1517. while ((c > vtfPath) && (*(c-1) != '.'))
  1518. {
  1519. --c;
  1520. }
  1521. *c = 0;
  1522. Q_strncat(vtfPath, "vtf", sizeof(vtfPath), COPY_ALL_CHARACTERS);
  1523. // get the vtfFilename from the path.
  1524. const char *vtfFilename = pInPath + strlen(pInPath);
  1525. while ((vtfFilename > pInPath) && (*(vtfFilename-1) != '\\') && (*(vtfFilename-1) != '/'))
  1526. {
  1527. --vtfFilename;
  1528. }
  1529. // Create a safe version of pOutDir with corrected slashes
  1530. char szOutDir[MAX_PATH*2];
  1531. V_strcpy_safe( szOutDir, IsPosix() ? "/materials/" : "\\materials\\" );
  1532. if ( pMaterialsSubDir[0] == '\\' || pMaterialsSubDir[0] == '/' )
  1533. pMaterialsSubDir = pMaterialsSubDir + 1;
  1534. Q_strcat(szOutDir, pMaterialsSubDir, sizeof(szOutDir) );
  1535. Q_StripTrailingSlash( szOutDir );
  1536. Q_AppendSlash( szOutDir, sizeof(szOutDir) );
  1537. Q_FixSlashes( szOutDir, CORRECT_PATH_SEPARATOR );
  1538. #ifdef ENGINE_DLL
  1539. Q_strncpy(finalPath, com_gamedir, sizeof(finalPath));
  1540. #elif REPLAY_DLL
  1541. Q_strncpy(finalPath, g_pEngine->GetGameDir(), sizeof(finalPath));
  1542. #elif defined(CLIENT_DLL) || defined(GAME_DLL)
  1543. Q_strncpy(finalPath, engine->GetGameDirectory(), sizeof(finalPath));
  1544. #endif
  1545. Q_strncat(finalPath, szOutDir, sizeof(finalPath), COPY_ALL_CHARACTERS);
  1546. Q_strncat(finalPath, vtfFilename, sizeof(finalPath), COPY_ALL_CHARACTERS);
  1547. c = finalPath + strlen(finalPath);
  1548. while ((c > finalPath) && (*(c-1) != '.'))
  1549. {
  1550. --c;
  1551. }
  1552. *c = 0;
  1553. Q_strncat(finalPath,"vtf", sizeof(finalPath), COPY_ALL_CHARACTERS);
  1554. // make sure the directory exists before we try to copy the file.
  1555. g_pFullFileSystem->CreateDirHierarchy(szOutDir + 1, "GAME");
  1556. //g_pFullFileSystem->CreateDirHierarchy("materials/VGUI/logos/", "GAME");
  1557. // write out the spray VMT file.
  1558. nErrorCode = ImgUtl_WriteGenericVMT(finalPath, pMaterialsSubDir);
  1559. if (nErrorCode != CE_SUCCESS)
  1560. {
  1561. failed = true;
  1562. }
  1563. if (!failed)
  1564. {
  1565. // copy vtf file to the final location.
  1566. DoCopyFile( vtfPath, finalPath );
  1567. }
  1568. }
  1569. // delete the intermediate VTF file if one was made.
  1570. if (deleteIntermediateVTF)
  1571. {
  1572. DoDeleteFile( vtfPath );
  1573. // the TGA->VTF conversion process generates a .txt file if one wasn't already there.
  1574. // in this case, delete the .txt file.
  1575. c = vtfPath + strlen(vtfPath);
  1576. while ((c > vtfPath) && (*(c-1) != '.'))
  1577. {
  1578. --c;
  1579. }
  1580. Q_strncpy(c, "txt", sizeof(vtfPath)-(c-vtfPath));
  1581. DoDeleteFile( vtfPath );
  1582. }
  1583. // delete the intermediate TGA file if one was made.
  1584. if (deleteIntermediateTGA)
  1585. {
  1586. DoDeleteFile( tgaPath );
  1587. }
  1588. return nErrorCode;
  1589. #endif
  1590. }
  1591. ConversionErrorType ImgUtl_WriteGenericVMT( const char *vtfPath, const char *pMaterialsSubDir )
  1592. {
  1593. if (vtfPath == NULL || pMaterialsSubDir == NULL )
  1594. {
  1595. return CE_ERROR_WRITING_OUTPUT_FILE;
  1596. }
  1597. // make the vmt filename
  1598. char vmtPath[MAX_PATH*4];
  1599. Q_strncpy(vmtPath, vtfPath, sizeof(vmtPath));
  1600. char *c = vmtPath + strlen(vmtPath);
  1601. while ((c > vmtPath) && (*(c-1) != '.'))
  1602. {
  1603. --c;
  1604. }
  1605. Q_strncpy(c, "vmt", sizeof(vmtPath) - (c - vmtPath));
  1606. // get the root filename for the vtf file
  1607. char filename[MAX_PATH];
  1608. while ((c > vmtPath) && (*(c-1) != '/') && (*(c-1) != '\\'))
  1609. {
  1610. --c;
  1611. }
  1612. int i = 0;
  1613. while ((*c != 0) && (*c != '.'))
  1614. {
  1615. filename[i++] = *(c++);
  1616. }
  1617. filename[i] = 0;
  1618. // create the vmt file.
  1619. FILE *vmtFile = fopen(vmtPath, "w");
  1620. if (vmtFile == NULL)
  1621. {
  1622. return CE_ERROR_WRITING_OUTPUT_FILE;
  1623. }
  1624. // make a copy of the subdir and remove any trailing slash
  1625. char szMaterialsSubDir[ MAX_PATH*2 ];
  1626. V_strcpy( szMaterialsSubDir, pMaterialsSubDir );
  1627. V_StripTrailingSlash( szMaterialsSubDir );
  1628. // fix slashes
  1629. V_FixSlashes( szMaterialsSubDir );
  1630. // write the contents of the file.
  1631. fprintf(vmtFile, "\"UnlitGeneric\"\n{\n\t\"$basetexture\" \"%s%c%s\"\n\t\"$translucent\" \"1\"\n\t\"$ignorez\" \"1\"\n\t\"$vertexcolor\" \"1\"\n\t\"$vertexalpha\" \"1\"\n}\n", szMaterialsSubDir, CORRECT_PATH_SEPARATOR, filename);
  1632. fclose(vmtFile);
  1633. return CE_SUCCESS;
  1634. }
  1635. static void WritePNGData( png_structp png_ptr, png_bytep inBytes, png_size_t byteCountToWrite )
  1636. {
  1637. // Cast pointer
  1638. CUtlBuffer *pBuf = (CUtlBuffer *)png_get_io_ptr( png_ptr );
  1639. Assert( pBuf );
  1640. // Write the bytes
  1641. pBuf->Put( inBytes, byteCountToWrite );
  1642. // What? Put() returns void. No way to detect error?
  1643. }
  1644. static void FlushPNGData( png_structp png_ptr )
  1645. {
  1646. // We're writing to a memory buffer, it's a NOP
  1647. }
  1648. ConversionErrorType ImgUtl_WriteRGBAAsPNGToBuffer( const unsigned char *pRGBAData, int nWidth, int nHeight, CUtlBuffer &bufOutData, int nStride )
  1649. {
  1650. #if !defined( _X360 ) && defined( WIN32 )
  1651. // Auto detect image stride
  1652. if ( nStride <= 0 )
  1653. {
  1654. nStride = nWidth*4;
  1655. }
  1656. /* could pass pointers to user-defined error handlers instead of NULLs: */
  1657. png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
  1658. NULL, NULL, NULL);
  1659. if (png_ptr == NULL)
  1660. {
  1661. return CE_MEMORY_ERROR;
  1662. }
  1663. ConversionErrorType errcode = CE_MEMORY_ERROR;
  1664. png_bytepp row_pointers = NULL;
  1665. png_infop info_ptr = png_create_info_struct(png_ptr);
  1666. if ( !info_ptr )
  1667. {
  1668. errcode = CE_MEMORY_ERROR;
  1669. fail:
  1670. if ( row_pointers )
  1671. {
  1672. free( row_pointers );
  1673. }
  1674. png_destroy_write_struct( &png_ptr, &info_ptr );
  1675. return errcode;
  1676. }
  1677. // We'll use the default setjmp / longjmp error handling.
  1678. if ( setjmp( png_ptr->png_jmpbuf ) )
  1679. {
  1680. // Error "writing". But since we're writing to a memory bufferm,
  1681. // that just means we must have run out of memory
  1682. errcode = CE_MEMORY_ERROR;
  1683. goto fail;
  1684. }
  1685. // Setup stream writing callbacks
  1686. png_set_write_fn(png_ptr, (void *)&bufOutData, WritePNGData, FlushPNGData);
  1687. // Setup info structure
  1688. png_set_IHDR(png_ptr, info_ptr, nWidth, nHeight, 8, PNG_COLOR_TYPE_RGB_ALPHA,
  1689. PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  1690. // !FIXME! Here we really should scan for the common case of
  1691. // an opaque image (all alpha=255) and strip the alpha channel
  1692. // in that case.
  1693. // Write the file header information.
  1694. png_write_info(png_ptr, info_ptr);
  1695. row_pointers = (png_bytepp)malloc( nHeight*sizeof(png_bytep) );
  1696. if ( row_pointers == NULL )
  1697. {
  1698. errcode = CE_MEMORY_ERROR;
  1699. goto fail;
  1700. }
  1701. /* set the individual row_pointers to point at the correct offsets */
  1702. for ( int i = 0; i < nHeight; ++i)
  1703. row_pointers[i] = const_cast<unsigned char *>(pRGBAData + i*nStride);
  1704. // Write the image
  1705. png_write_image(png_ptr, row_pointers);
  1706. /* It is REQUIRED to call this to finish writing the rest of the file */
  1707. png_write_end(png_ptr, info_ptr);
  1708. // Clean up, and we're done
  1709. free( row_pointers );
  1710. row_pointers = NULL;
  1711. png_destroy_write_struct(&png_ptr, &info_ptr);
  1712. return CE_SUCCESS;
  1713. #else
  1714. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1715. #endif
  1716. }
  1717. //-----------------------------------------------------------------------------
  1718. // Purpose: Initialize destination --- called by jpeg_start_compress
  1719. // before any data is actually written.
  1720. //-----------------------------------------------------------------------------
  1721. METHODDEF(void) init_destination (j_compress_ptr cinfo)
  1722. {
  1723. JPEGDestinationManager_t *dest = ( JPEGDestinationManager_t *) cinfo->dest;
  1724. // Allocate the output buffer --- it will be released when done with image
  1725. dest->buffer = (byte *)
  1726. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  1727. JPEG_OUTPUT_BUF_SIZE * sizeof(byte));
  1728. dest->pub.next_output_byte = dest->buffer;
  1729. dest->pub.free_in_buffer = JPEG_OUTPUT_BUF_SIZE;
  1730. }
  1731. //-----------------------------------------------------------------------------
  1732. // Purpose: Empty the output buffer --- called whenever buffer fills up.
  1733. // Input : boolean -
  1734. //-----------------------------------------------------------------------------
  1735. METHODDEF(boolean) empty_output_buffer (j_compress_ptr cinfo)
  1736. {
  1737. JPEGDestinationManager_t *dest = ( JPEGDestinationManager_t * ) cinfo->dest;
  1738. CUtlBuffer *buf = dest->pBuffer;
  1739. // Add some data
  1740. buf->Put( dest->buffer, JPEG_OUTPUT_BUF_SIZE );
  1741. dest->pub.next_output_byte = dest->buffer;
  1742. dest->pub.free_in_buffer = JPEG_OUTPUT_BUF_SIZE;
  1743. return TRUE;
  1744. }
  1745. //-----------------------------------------------------------------------------
  1746. // Purpose: Terminate destination --- called by jpeg_finish_compress
  1747. // after all data has been written. Usually needs to flush buffer.
  1748. //
  1749. // NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
  1750. // application must deal with any cleanup that should happen even
  1751. // for error exit.
  1752. //-----------------------------------------------------------------------------
  1753. METHODDEF(void) term_destination (j_compress_ptr cinfo)
  1754. {
  1755. JPEGDestinationManager_t *dest = (JPEGDestinationManager_t *) cinfo->dest;
  1756. size_t datacount = JPEG_OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
  1757. CUtlBuffer *buf = dest->pBuffer;
  1758. /* Write any data remaining in the buffer */
  1759. if (datacount > 0)
  1760. {
  1761. buf->Put( dest->buffer, datacount );
  1762. }
  1763. }
  1764. //-----------------------------------------------------------------------------
  1765. // Purpose: Set up functions for writing data to a CUtlBuffer instead of FILE *
  1766. //-----------------------------------------------------------------------------
  1767. GLOBAL(void) jpeg_UtlBuffer_dest (j_compress_ptr cinfo, CUtlBuffer *pBuffer )
  1768. {
  1769. JPEGDestinationManager_t *dest;
  1770. /* The destination object is made permanent so that multiple JPEG images
  1771. * can be written to the same file without re-executing jpeg_stdio_dest.
  1772. * This makes it dangerous to use this manager and a different destination
  1773. * manager serially with the same JPEG object, because their private object
  1774. * sizes may be different. Caveat programmer.
  1775. */
  1776. if (cinfo->dest == NULL) { /* first time for this JPEG object? */
  1777. cinfo->dest = (struct jpeg_destination_mgr *)
  1778. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  1779. sizeof(JPEGDestinationManager_t));
  1780. }
  1781. dest = ( JPEGDestinationManager_t * ) cinfo->dest;
  1782. dest->pub.init_destination = init_destination;
  1783. dest->pub.empty_output_buffer = empty_output_buffer;
  1784. dest->pub.term_destination = term_destination;
  1785. dest->pBuffer = pBuffer;
  1786. }
  1787. //-----------------------------------------------------------------------------
  1788. // Purpose: Write three channel RGB data to a JPEG file
  1789. //-----------------------------------------------------------------------------
  1790. bool ImgUtl_WriteRGBToJPEG( unsigned char *pSrcBuf, unsigned int nSrcWidth, unsigned int nSrcHeight, const char *lpszFilename )
  1791. {
  1792. CUtlBuffer dstBuf;
  1793. JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s]
  1794. int row_stride; // physical row width in image buffer
  1795. // stderr handler
  1796. struct jpeg_error_mgr jerr;
  1797. // compression data structure
  1798. struct jpeg_compress_struct cinfo;
  1799. row_stride = nSrcWidth * 3; // JSAMPLEs per row in image_buffer
  1800. // point at stderr
  1801. cinfo.err = jpeg_std_error(&jerr);
  1802. // create compressor
  1803. jpeg_create_compress(&cinfo);
  1804. // Hook CUtlBuffer to compression
  1805. jpeg_UtlBuffer_dest(&cinfo, &dstBuf );
  1806. // image width and height, in pixels
  1807. cinfo.image_width = nSrcWidth;
  1808. cinfo.image_height = nSrcHeight;
  1809. // RGB is 3 component
  1810. cinfo.input_components = 3;
  1811. // # of color components per pixel
  1812. cinfo.in_color_space = JCS_RGB;
  1813. // Apply settings
  1814. jpeg_set_defaults(&cinfo);
  1815. jpeg_set_quality(&cinfo, 100, TRUE );
  1816. // Start compressor
  1817. jpeg_start_compress(&cinfo, TRUE);
  1818. // Write scanlines
  1819. while ( cinfo.next_scanline < cinfo.image_height )
  1820. {
  1821. row_pointer[ 0 ] = &pSrcBuf[ cinfo.next_scanline * row_stride ];
  1822. jpeg_write_scanlines( &cinfo, row_pointer, 1 );
  1823. }
  1824. // Finalize image
  1825. jpeg_finish_compress(&cinfo);
  1826. // Cleanup
  1827. jpeg_destroy_compress(&cinfo);
  1828. return CE_SUCCESS;
  1829. }
  1830. ConversionErrorType ImgUtl_WriteRGBAAsJPEGToBuffer( const unsigned char *pRGBAData, int nWidth, int nHeight, CUtlBuffer &bufOutData, int nStride )
  1831. {
  1832. #if !defined( _X360 )
  1833. JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s]
  1834. int row_stride; // physical row width in image buffer
  1835. // stderr handler
  1836. struct jpeg_error_mgr jerr;
  1837. // compression data structure
  1838. struct jpeg_compress_struct cinfo;
  1839. row_stride = nWidth * 4;
  1840. // point at stderr
  1841. cinfo.err = jpeg_std_error(&jerr);
  1842. // create compressor
  1843. jpeg_create_compress(&cinfo);
  1844. // Hook CUtlBuffer to compression
  1845. jpeg_UtlBuffer_dest(&cinfo, &bufOutData );
  1846. // image width and height, in pixels
  1847. cinfo.image_width = nWidth;
  1848. cinfo.image_height = nHeight;
  1849. // RGB is 3 component
  1850. cinfo.input_components = 3;
  1851. // # of color components per pixel
  1852. cinfo.in_color_space = JCS_RGB;
  1853. // Apply settings
  1854. jpeg_set_defaults(&cinfo);
  1855. jpeg_set_quality(&cinfo, 100, TRUE );
  1856. // Start compressor
  1857. jpeg_start_compress(&cinfo, TRUE);
  1858. // Write scanlines
  1859. unsigned char *pDstRow = (unsigned char *)malloc( sizeof(unsigned char) * nWidth * 4 );
  1860. while ( cinfo.next_scanline < cinfo.image_height )
  1861. {
  1862. const unsigned char *pSrcRow = &(pRGBAData[cinfo.next_scanline * row_stride]);
  1863. // convert row from RGBA to RGB
  1864. for ( int x = nWidth-1 ; x >= 0 ; --x )
  1865. {
  1866. pDstRow[x*3+2] = pSrcRow[x*4+2];
  1867. pDstRow[x*3+1] = pSrcRow[x*4+1];
  1868. pDstRow[x*3] = pSrcRow[x*4];
  1869. }
  1870. row_pointer[ 0 ] = pDstRow;
  1871. jpeg_write_scanlines( &cinfo, row_pointer, 1 );
  1872. }
  1873. // Finalize image
  1874. jpeg_finish_compress(&cinfo);
  1875. // Cleanup
  1876. jpeg_destroy_compress(&cinfo);
  1877. free( pDstRow );
  1878. return CE_SUCCESS;
  1879. #else
  1880. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1881. #endif
  1882. }
  1883. ConversionErrorType ImgUtl_LoadBitmap( const char *pszFilename, Bitmap_t &bitmap )
  1884. {
  1885. bitmap.Clear();
  1886. ConversionErrorType nErrorCode;
  1887. int width, height;
  1888. unsigned char *buffer = ImgUtl_ReadImageAsRGBA( pszFilename, width, height, nErrorCode );
  1889. if ( nErrorCode != CE_SUCCESS )
  1890. {
  1891. return nErrorCode;
  1892. }
  1893. // Install the buffer into the bitmap, and transfer ownership
  1894. bitmap.SetBuffer( width, height, IMAGE_FORMAT_RGBA8888, buffer, true, width*4 );
  1895. return CE_SUCCESS;
  1896. }
  1897. static ConversionErrorType ImgUtl_LoadJPEGBitmapFromBuffer( CUtlBuffer &fileData, Bitmap_t &bitmap )
  1898. {
  1899. // @todo implement
  1900. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1901. }
  1902. static ConversionErrorType ImgUtl_SaveJPEGBitmapToBuffer( CUtlBuffer &fileData, const Bitmap_t &bitmap )
  1903. {
  1904. if ( !bitmap.IsValid() )
  1905. {
  1906. Assert( bitmap.IsValid() );
  1907. return CE_CANT_OPEN_SOURCE_FILE;
  1908. }
  1909. // Sorry, only RGBA8888 supported right now
  1910. if ( bitmap.Format() != IMAGE_FORMAT_RGBA8888 )
  1911. {
  1912. Assert( bitmap.Format() == IMAGE_FORMAT_RGBA8888 );
  1913. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1914. }
  1915. // Do it
  1916. ConversionErrorType result = ImgUtl_WriteRGBAAsJPEGToBuffer(
  1917. bitmap.GetBits(),
  1918. bitmap.Width(),
  1919. bitmap.Height(),
  1920. fileData,
  1921. bitmap.Stride()
  1922. );
  1923. return result;
  1924. }
  1925. ConversionErrorType ImgUtl_LoadBitmapFromBuffer( CUtlBuffer &fileData, Bitmap_t &bitmap, ImageFileFormat eImageFileFormat )
  1926. {
  1927. switch ( eImageFileFormat )
  1928. {
  1929. case kImageFileFormat_PNG:
  1930. return ImgUtl_LoadPNGBitmapFromBuffer( fileData, bitmap );
  1931. case kImageFileFormat_JPG:
  1932. return ImgUtl_LoadJPEGBitmapFromBuffer( fileData, bitmap );
  1933. }
  1934. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1935. }
  1936. ConversionErrorType ImgUtl_SaveBitmapToBuffer( CUtlBuffer &fileData, const Bitmap_t &bitmap, ImageFileFormat eImageFileFormat )
  1937. {
  1938. switch ( eImageFileFormat )
  1939. {
  1940. case kImageFileFormat_PNG:
  1941. return ImgUtl_SavePNGBitmapToBuffer( fileData, bitmap );
  1942. case kImageFileFormat_JPG:
  1943. return ImgUtl_SaveJPEGBitmapToBuffer( fileData, bitmap );
  1944. }
  1945. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1946. }
  1947. ConversionErrorType ImgUtl_LoadPNGBitmapFromBuffer( CUtlBuffer &fileData, Bitmap_t &bitmap )
  1948. {
  1949. bitmap.Clear();
  1950. ConversionErrorType nErrorCode;
  1951. int width, height;
  1952. unsigned char *buffer = ImgUtl_ReadPNGAsRGBAFromBuffer( fileData, width, height, nErrorCode );
  1953. if ( nErrorCode != CE_SUCCESS )
  1954. {
  1955. return nErrorCode;
  1956. }
  1957. // Install the buffer into the bitmap, and transfer ownership
  1958. bitmap.SetBuffer( width, height, IMAGE_FORMAT_RGBA8888, buffer, true, width*4 );
  1959. return CE_SUCCESS;
  1960. }
  1961. ConversionErrorType ImgUtl_SavePNGBitmapToBuffer( CUtlBuffer &fileData, const Bitmap_t &bitmap )
  1962. {
  1963. if ( !bitmap.IsValid() )
  1964. {
  1965. Assert( bitmap.IsValid() );
  1966. return CE_CANT_OPEN_SOURCE_FILE;
  1967. }
  1968. // Sorry, only RGBA8888 supported right now
  1969. if ( bitmap.Format() != IMAGE_FORMAT_RGBA8888 )
  1970. {
  1971. Assert( bitmap.Format() == IMAGE_FORMAT_RGBA8888 );
  1972. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1973. }
  1974. // Do it
  1975. ConversionErrorType result = ImgUtl_WriteRGBAAsPNGToBuffer(
  1976. bitmap.GetBits(),
  1977. bitmap.Width(),
  1978. bitmap.Height(),
  1979. fileData,
  1980. bitmap.Stride()
  1981. );
  1982. return result;
  1983. }
  1984. ConversionErrorType ImgUtl_ResizeBitmap( Bitmap_t &destBitmap, int nWidth, int nHeight, const Bitmap_t *pImgSource )
  1985. {
  1986. // Check for resizing in place, then save off data into a temp
  1987. Bitmap_t temp;
  1988. if ( pImgSource == NULL || pImgSource == &destBitmap )
  1989. {
  1990. temp.MakeLogicalCopyOf( destBitmap, destBitmap.GetOwnsBuffer() );
  1991. pImgSource = &temp;
  1992. }
  1993. // No source image?
  1994. if ( !pImgSource->IsValid() )
  1995. {
  1996. Assert( pImgSource->IsValid() );
  1997. return CE_CANT_OPEN_SOURCE_FILE;
  1998. }
  1999. // Sorry, we're using an existing rescaling routine that
  2000. // only withs for RGBA images with assumed stride
  2001. if (
  2002. pImgSource->Format() != IMAGE_FORMAT_RGBA8888
  2003. || pImgSource->Stride() != pImgSource->Width()*4
  2004. ) {
  2005. Assert( pImgSource->Format() == IMAGE_FORMAT_RGBA8888 );
  2006. Assert( pImgSource->Stride() == pImgSource->Width()*4 );
  2007. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  2008. }
  2009. // Allocate buffer
  2010. destBitmap.Init( nWidth, nHeight, IMAGE_FORMAT_RGBA8888 );
  2011. // Something wrong?
  2012. if ( !destBitmap.IsValid() )
  2013. {
  2014. Assert( destBitmap.IsValid() );
  2015. return CE_MEMORY_ERROR;
  2016. }
  2017. // Do it
  2018. return ImgUtl_StretchRGBAImage(
  2019. pImgSource->GetBits(), pImgSource->Width(), pImgSource->Height(),
  2020. destBitmap.GetBits(), destBitmap.Width(), destBitmap.Height()
  2021. );
  2022. }
  2023. //-----------------------------------------------------------------------------
  2024. // Purpose: Read a JPEG from disk
  2025. //-----------------------------------------------------------------------------
  2026. ConversionErrorType ImgUtl_ReadJPEGToRGB( CUtlBuffer &srcBuf, CUtlBuffer &dstBuf, int &width, int &height )
  2027. {
  2028. // Point directly to our CUtlBuffer data
  2029. CJpegSourceMgr jpgMgr;
  2030. jpgMgr.bytes_in_buffer = srcBuf.Size();
  2031. jpgMgr.next_input_byte = (unsigned char*) srcBuf.Base();
  2032. // Load the jpeg.
  2033. struct jpeg_decompress_struct jpegInfo;
  2034. struct jpeg_error_mgr jerr;
  2035. memset( &jpegInfo, 0, sizeof( jpegInfo ) );
  2036. jpegInfo.err = jpeg_std_error(&jerr);
  2037. jpeg_create_decompress(&jpegInfo);
  2038. jpegInfo.src = &jpgMgr;
  2039. jpegInfo.err->error_exit = &ValveJpegErrorHandler;
  2040. if ( jpeg_read_header( &jpegInfo, TRUE ) != JPEG_HEADER_OK)
  2041. return CE_ERROR_PARSING_SOURCE;
  2042. // start the decompress with the jpeg engine.
  2043. if ( !jpeg_start_decompress( &jpegInfo ) || jpegInfo.output_components != 3)
  2044. {
  2045. jpeg_destroy_decompress(&jpegInfo);
  2046. return CE_ERROR_PARSING_SOURCE;
  2047. }
  2048. // now that we've started the decompress with the jpeg lib, we have the attributes of the
  2049. // image ready to be read out of the decompress struct.
  2050. int row_stride = jpegInfo.output_width * jpegInfo.output_components;
  2051. int mem_required = jpegInfo.image_height * jpegInfo.image_width * jpegInfo.output_components;
  2052. JSAMPROW row_pointer[1];
  2053. int cur_row = 0;
  2054. width = jpegInfo.output_width;
  2055. height = jpegInfo.output_height;
  2056. // Alloc a temporary buffer to serialize to
  2057. dstBuf.EnsureCapacity( mem_required );
  2058. unsigned char *pDstBuf = (unsigned char *) dstBuf.PeekPut();
  2059. // read in all the scan lines of the image into our image data buffer.
  2060. bool working = true;
  2061. while (working && (jpegInfo.output_scanline < jpegInfo.output_height))
  2062. {
  2063. row_pointer[0] = &(pDstBuf[cur_row * row_stride]);
  2064. if (!jpeg_read_scanlines(&jpegInfo, row_pointer, 1) )
  2065. {
  2066. working = false;
  2067. }
  2068. ++cur_row;
  2069. }
  2070. if (!working)
  2071. {
  2072. jpeg_destroy_decompress(&jpegInfo);
  2073. return CE_ERROR_PARSING_SOURCE;
  2074. }
  2075. jpeg_finish_decompress(&jpegInfo);
  2076. // Place our read point at the end of the file
  2077. dstBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, mem_required );
  2078. return CE_SUCCESS;
  2079. }
  2080. //-----------------------------------------------------------------------------
  2081. // Purpose: Take our RGBA buffer and crop it down to a proper size with offset
  2082. //-----------------------------------------------------------------------------
  2083. ConversionErrorType ImgUtl_CropRGBA( int x0, int y0, int nSrcWidth, int nSrcHeight, int nDestWidth, int nDestHeight, const unsigned char *pIn, unsigned char *pOut )
  2084. {
  2085. // Allocate new buffer
  2086. const int nRowSize = nDestWidth * 4;
  2087. // Copy data, one row at a time
  2088. for ( int y = 0 ; y < nDestHeight; ++y )
  2089. {
  2090. memcpy( pOut + y*nRowSize, pIn + ( ((y0+y)*nSrcWidth) + x0 ) * 4, nRowSize );
  2091. }
  2092. return CE_SUCCESS;
  2093. }
  2094. //-----------------------------------------------------------------------------
  2095. // Purpose: Write three channel RGB data to a JPEG file
  2096. //-----------------------------------------------------------------------------
  2097. bool ImgUtl_WriteRGBAToJPEG( unsigned char *pSrcBuf, unsigned int nSrcWidth, unsigned int nSrcHeight, const char *lpszFilename )
  2098. {
  2099. CUtlBuffer dstBuf;
  2100. JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s]
  2101. int row_stride; // physical row width in image buffer
  2102. // compression data structure
  2103. struct jpeg_compress_struct cinfo;
  2104. unsigned char *pConvBuf;
  2105. pConvBuf = (unsigned char *) malloc( nSrcHeight * nSrcWidth * ImageLoader::SizeInBytes( IMAGE_FORMAT_RGB888 ) );
  2106. if ( pConvBuf == NULL )
  2107. return CE_MEMORY_ERROR;
  2108. ImageLoader::ConvertImageFormat( pSrcBuf, IMAGE_FORMAT_RGBA8888, pConvBuf, IMAGE_FORMAT_RGB888, nSrcWidth, nSrcHeight );
  2109. row_stride = nSrcWidth * 3; // JSAMPLEs per row in image_buffer
  2110. struct ValveJpegErrorHandler_t jerr;
  2111. cinfo.err = jpeg_std_error(&jerr.m_Base);
  2112. cinfo.err->error_exit = &ValveJpegErrorHandler;
  2113. // create compressor
  2114. jpeg_create_compress(&cinfo);
  2115. // Hook CUtlBuffer to compression
  2116. jpeg_UtlBuffer_dest(&cinfo, &dstBuf );
  2117. // Handle our error case
  2118. if ( setjmp( jerr.m_ErrorContext ) )
  2119. {
  2120. free( pConvBuf );
  2121. return CE_ERROR_PARSING_SOURCE;
  2122. }
  2123. // image width and height, in pixels
  2124. cinfo.image_width = nSrcWidth;
  2125. cinfo.image_height = nSrcHeight;
  2126. // RGBA is 3 components
  2127. cinfo.input_components = 3;
  2128. // # of color components per pixel
  2129. cinfo.in_color_space = JCS_RGB;
  2130. // Apply settings
  2131. jpeg_set_defaults(&cinfo);
  2132. jpeg_set_quality(&cinfo, 100, TRUE );
  2133. // Start compressor
  2134. jpeg_start_compress(&cinfo, TRUE);
  2135. // Write scanlines
  2136. while ( cinfo.next_scanline < cinfo.image_height )
  2137. {
  2138. row_pointer[ 0 ] = &pConvBuf[ cinfo.next_scanline * row_stride ];
  2139. jpeg_write_scanlines( &cinfo, row_pointer, 1 );
  2140. }
  2141. // Finalize image
  2142. jpeg_finish_compress(&cinfo);
  2143. // Cleanup
  2144. jpeg_destroy_compress(&cinfo);
  2145. free( pConvBuf );
  2146. int finalSize = 0;
  2147. FileHandle_t fh = g_pFullFileSystem->Open( lpszFilename, "wb", "LOCAL" );
  2148. if ( FILESYSTEM_INVALID_HANDLE != fh )
  2149. {
  2150. g_pFullFileSystem->Write( dstBuf.Base(), dstBuf.TellPut(), fh );
  2151. finalSize = g_pFullFileSystem->Tell( fh );
  2152. g_pFullFileSystem->Close( fh );
  2153. }
  2154. return CE_SUCCESS;
  2155. }