main.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include <stdlib.h>
  23. #include "/usr/local/include/png.h"
  24. #include "/usr/local/include/pngconf.h"
  25. //#include "stdafx.h"
  26. //#include "C:\\Program Files\\GnuWin32\\include\\png.h"
  27. #define MAX_ARGS 10
  28. #define TEMP_OUTPUT_FILE "xxtempxx.pvr"
  29. #define TEST_PVR_FILE "compare.pvr"
  30. extern bool readPvr( FILE* fp);
  31. extern bool writePvr( FILE* fp);
  32. bool readPNG( char *filename);
  33. int gBitsPerPixel = -1;
  34. int gChannelWeight = -1;
  35. int gGenerateMipMaps = -1;
  36. char gPNGFileName[256];
  37. char gPVRFileName[256];
  38. unsigned long gWidth;
  39. unsigned long gHeight;
  40. int gBitDepth;
  41. int gColorType;
  42. long gFsize;
  43. bool gIsAlpha;
  44. bool parseArgs(int argc, char * const argv[]);
  45. void usage();
  46. int main (int argc, char * const argv[]) {
  47. #if 0
  48. FILE *tf;
  49. tf = fopen(TEST_PVR_FILE, "rb");
  50. readPvr(tf);
  51. fclose(tf);
  52. #endif
  53. FILE *wf;
  54. FILE *rf;
  55. // insert code here...
  56. memset(gPNGFileName,0,256);
  57. memset(gPVRFileName,0,256);
  58. if(parseArgs(argc, argv)){
  59. #if 1
  60. char *argv2[MAX_ARGS];
  61. for(int i=0; i<MAX_ARGS-1; i++){
  62. argv2[i] = new char[256];
  63. }
  64. strcpy(argv2[0],"texturetool");
  65. strcpy(argv2[1],"-e");
  66. strcpy(argv2[2],"PVRTC");
  67. if(gChannelWeight==0){
  68. strcpy(argv2[3],"--channel-weighting-linear");
  69. }
  70. else if(gChannelWeight==1){
  71. strcpy(argv2[3],"--channel-weighting-perceptual");
  72. }
  73. else{
  74. usage();
  75. return -1;
  76. }
  77. if(gBitsPerPixel==2){
  78. strcpy(argv2[4],"--bits-per-pixel-2");
  79. }
  80. else if(gBitsPerPixel==4){
  81. strcpy(argv2[4],"--bits-per-pixel-4");
  82. }
  83. else{
  84. usage();
  85. return -1;
  86. }
  87. strcpy(argv2[5],gPNGFileName);
  88. strcpy(argv2[6],"-o");
  89. strcpy(argv2[7],TEMP_OUTPUT_FILE);
  90. if(gGenerateMipMaps==1){
  91. strcpy(argv2[8],"-m");
  92. }
  93. else{
  94. delete argv2[MAX_ARGS-2];
  95. argv2[MAX_ARGS-2] = NULL;
  96. }
  97. argv2[MAX_ARGS-1] = NULL;
  98. char *newargs = new char[8*1024];
  99. memset(newargs, 0, 8*1024);
  100. sprintf(newargs,"./%s",argv2[0]);
  101. for(int i=1; i<MAX_ARGS-1; i++){
  102. if(argv2[i]){
  103. strcat(newargs," ");
  104. strcat(newargs,argv2[i]);
  105. }
  106. }
  107. system(newargs);
  108. //if(execv("texturetool", argv2)<0){
  109. // usage();
  110. // return -1;
  111. //}
  112. delete newargs;
  113. //printf("\nHere %d\n",gFsize);
  114. if(!readPNG(gPNGFileName)){
  115. usage();
  116. return -1;
  117. }
  118. wf = fopen(gPVRFileName, "wb");
  119. if(!wf){
  120. printf("\nCannot open file %s\n\n",gPVRFileName);
  121. return -1;
  122. }
  123. #endif
  124. rf = fopen(TEMP_OUTPUT_FILE, "rb");
  125. if(!rf){
  126. printf("\nCannot open file %s\n\n",TEMP_OUTPUT_FILE);
  127. return -1;
  128. }
  129. fseek(rf,0,SEEK_END);
  130. gFsize = ftell(rf);
  131. //printf("\nHere %d\n",gFsize);
  132. fseek(rf,0,SEEK_SET);
  133. char *filedata = new char[gFsize];
  134. fread(filedata,1,gFsize,rf);
  135. fclose(rf);
  136. writePvr(wf);
  137. fwrite(filedata,1,gFsize,wf);
  138. fclose(wf);
  139. delete filedata;
  140. return 0;
  141. }
  142. usage();
  143. return -1;
  144. }
  145. void usage(){
  146. printf("\n");
  147. printf("Usage: PVRTC_Mac [-m] -b# -wX -i <input_png> -o <output_pvr>");
  148. printf("\n");
  149. printf(" -m Generate a complete mipmap chain from the input image.\n");
  150. printf(" -b# Bits per pixel either 2 or 4 is valid.\n");
  151. printf(" -wX Encoding either l = linear or p = perceptual.\n");
  152. printf(" -i <input> <input> PNG file must be square power of 2.\n");
  153. printf(" -o <output> Write processed image to <output>.");
  154. printf("\n\n");
  155. printf("Example:\n");
  156. printf(" PVRTC_Mac -b2 -wp -i my.png -o my.pvr\n\n");
  157. printf("This Will encode my.png with perceptual coding at 2 bits per pixel and output my.pvr.\n");
  158. printf("\n\n");
  159. /*
  160. Usage: texturetool [-hlm] [-e <encoder>] [-p <preview_file>] -o <output> [-f <format>] input_image
  161. -h Display this help menu.
  162. -l List available encoders, individual encoder options, and file formats.
  163. -m Generate a complete mipmap chain from the input image.
  164. -e <encoder> Encode texture levels with <encoder>.
  165. -p <preview_file> Output a PNG preview of the encoded output to <preview_file>. Requires -e option.
  166. -o <output> Write processed image to <output>.
  167. -f <format> Set file <format> for <output> image.
  168. PVRTC
  169. --channel-weighting-linear
  170. --channel-weighting-perceptual
  171. --bits-per-pixel-2
  172. --bits-per-pixel-4
  173. Formats:
  174. Raw
  175. PVR
  176. */
  177. }
  178. bool parseArgs(int argc, char * const argv[]){
  179. if(argc < 7) return false;
  180. for(int i=1; i<argc; i++){
  181. if(strcmp(argv[i],"-b2")==0){
  182. gBitsPerPixel = 2;
  183. }
  184. if(strcmp(argv[i],"-b4")==0){
  185. gBitsPerPixel = 4;
  186. }
  187. if(strcmp(argv[i],"-wl")==0){
  188. gChannelWeight = 0;
  189. }
  190. if(strcmp(argv[i],"-wp")==0){
  191. gChannelWeight = 1;
  192. }
  193. if(strcmp(argv[i],"-m")==0){
  194. gGenerateMipMaps = 1;
  195. }
  196. if(strcmp(argv[i],"-i")==0){
  197. i++;
  198. if(i<argc){
  199. strcpy(gPNGFileName,argv[i]);
  200. }
  201. else{
  202. return false;
  203. }
  204. }
  205. if(strcmp(argv[i],"-o")==0){
  206. i++;
  207. if(i<argc){
  208. strcpy(gPVRFileName,argv[i]);
  209. }
  210. else{
  211. return false;
  212. }
  213. }
  214. }
  215. return true;
  216. }
  217. //--------------------------------------
  218. static void pngFatalErrorFn(png_structp /*png_ptr*/,
  219. png_const_charp pMessage)
  220. {
  221. printf("Error reading PNG file:\n %s", pMessage);
  222. }
  223. //--------------------------------------
  224. static void pngWarningFn(png_structp, png_const_charp pMessage)
  225. {
  226. printf("Warning reading PNG file:\n %s", pMessage);
  227. }
  228. png_voidp gPngErrorPtr;
  229. bool readPNG( char *filename){
  230. static const unsigned int cs_headerBytesChecked = 8;
  231. unsigned char header[cs_headerBytesChecked];
  232. FILE *fp = fopen(filename, "rb");
  233. if (!fp)
  234. {
  235. return false;
  236. }
  237. fread(header, 1, cs_headerBytesChecked, fp);
  238. bool is_png = !png_sig_cmp(header, 0, cs_headerBytesChecked);
  239. if (!is_png)
  240. {
  241. fclose(fp);
  242. return false;
  243. }
  244. png_structp png_ptr = png_create_read_struct
  245. (PNG_LIBPNG_VER_STRING, (png_voidp)gPngErrorPtr,
  246. pngFatalErrorFn, pngWarningFn);
  247. if (!png_ptr){
  248. fclose(fp);
  249. return false;
  250. }
  251. png_infop info_ptr = png_create_info_struct(png_ptr);
  252. if (!info_ptr)
  253. {
  254. png_destroy_read_struct(&png_ptr,
  255. (png_infopp)NULL, (png_infopp)NULL);
  256. fclose(fp);
  257. return false;
  258. }
  259. png_infop end_info = png_create_info_struct(png_ptr);
  260. if (!end_info)
  261. {
  262. png_destroy_read_struct(&png_ptr, &info_ptr,
  263. (png_infopp)NULL);
  264. fclose(fp);
  265. return false;
  266. }
  267. if (setjmp(png_jmpbuf(png_ptr)))
  268. {
  269. png_destroy_read_struct(&png_ptr, &info_ptr,
  270. &end_info);
  271. fclose(fp);
  272. return false;
  273. }
  274. png_init_io(png_ptr, fp);
  275. png_set_sig_bytes(png_ptr, cs_headerBytesChecked);
  276. png_read_info(png_ptr, info_ptr);
  277. png_get_IHDR(png_ptr, info_ptr,
  278. &gWidth, &gHeight, // obv.
  279. &gBitDepth, &gColorType, // obv.
  280. NULL, // interlace
  281. NULL, // compression_type
  282. NULL); // filter_type
  283. bool transAlpha = false;
  284. gIsAlpha = false;
  285. if(gWidth != gHeight){
  286. printf("Not a square input image %dx%d\n",gWidth,gHeight);
  287. return false;
  288. }
  289. if(gWidth > 1024){
  290. printf("Image %dx%d is too large for iPhone\n",gWidth,gHeight);
  291. return false;
  292. }
  293. int count = 0;
  294. int temp = gWidth;
  295. while(temp > 0){
  296. count += temp & 1;
  297. temp >>= 1;
  298. }
  299. if(count != 1){
  300. printf("Not a power of 2 image %dx%d\n",gWidth,gHeight);
  301. return false;
  302. }
  303. // Expand a transparency channel into a full alpha channel...
  304. //
  305. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
  306. transAlpha = true;
  307. }
  308. if (gColorType == PNG_COLOR_TYPE_PALETTE)
  309. {
  310. gIsAlpha = transAlpha;
  311. }
  312. else if (gColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
  313. {
  314. gIsAlpha = true;
  315. }
  316. else if (gColorType == PNG_COLOR_TYPE_RGB_ALPHA)
  317. {
  318. gIsAlpha = true;
  319. }
  320. fclose(fp);
  321. return true;
  322. }
  323. /*
  324. static void pngReadDataFn(png_structp png_ptr,
  325. png_bytep data,
  326. png_size_t length)
  327. {
  328. bool success = sg_pStream->read(length, data);
  329. }
  330. //--------------------------------------
  331. static void pngWriteDataFn(png_structp png_ptr,
  332. png_bytep data,
  333. png_size_t length)
  334. {
  335. AssertFatal(sg_pStream != NULL, "No stream?");
  336. sg_pStream->write(length, data);
  337. }
  338. //--------------------------------------
  339. static void pngFlushDataFn(png_structp png_ptr)
  340. {
  341. //
  342. }
  343. */
  344. /*
  345. //--------------------------------------
  346. bool GBitmap::readPNG(Stream& io_rStream)
  347. {
  348. static const U32 cs_headerBytesChecked = 8;
  349. U8 header[cs_headerBytesChecked];
  350. io_rStream.read(cs_headerBytesChecked, header);
  351. bool isPng = png_check_sig(header, cs_headerBytesChecked) != 0;
  352. if (isPng == false)
  353. {
  354. AssertWarn(false, "GBitmap::readPNG: stream doesn't contain a PNG");
  355. return false;
  356. }
  357. U32 prevWaterMark = FrameAllocator::getWaterMark();
  358. #if defined(PNG_USER_MEM_SUPPORTED)
  359. png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
  360. NULL,
  361. pngFatalErrorFn,
  362. pngWarningFn,
  363. NULL,
  364. pngMallocFn,
  365. pngFreeFn);
  366. #else
  367. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  368. NULL,
  369. pngFatalErrorFn,
  370. pngWarningFn);
  371. #endif
  372. if (png_ptr == NULL)
  373. {
  374. FrameAllocator::setWaterMark(prevWaterMark);
  375. return false;
  376. }
  377. // Enable optimizations if appropriate.
  378. #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
  379. png_uint_32 mask, flags;
  380. flags = png_get_asm_flags(png_ptr);
  381. mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
  382. png_set_asm_flags(png_ptr, flags | mask);
  383. #endif
  384. png_infop info_ptr = png_create_info_struct(png_ptr);
  385. if (info_ptr == NULL) {
  386. png_destroy_read_struct(&png_ptr,
  387. (png_infopp)NULL,
  388. (png_infopp)NULL);
  389. FrameAllocator::setWaterMark(prevWaterMark);
  390. return false;
  391. }
  392. png_infop end_info = png_create_info_struct(png_ptr);
  393. if (end_info == NULL) {
  394. png_destroy_read_struct(&png_ptr,
  395. &info_ptr,
  396. (png_infopp)NULL);
  397. FrameAllocator::setWaterMark(prevWaterMark);
  398. return false;
  399. }
  400. sg_pStream = &io_rStream;
  401. png_set_read_fn(png_ptr, NULL, pngReadDataFn);
  402. // Read off the info on the image.
  403. png_set_sig_bytes(png_ptr, cs_headerBytesChecked);
  404. png_read_info(png_ptr, info_ptr);
  405. // OK, at this point, if we have reached it ok, then we can reset the
  406. // image to accept the new data...
  407. //
  408. deleteImage();
  409. png_uint_32 width;
  410. png_uint_32 height;
  411. S32 bit_depth;
  412. S32 color_type;
  413. png_get_IHDR(png_ptr, info_ptr,
  414. &width, &height, // obv.
  415. &bit_depth, &color_type, // obv.
  416. NULL, // interlace
  417. NULL, // compression_type
  418. NULL); // filter_type
  419. // First, handle the color transformations. We need this to read in the
  420. // data as RGB or RGBA, _always_, with a maximal channel width of 8 bits.
  421. //
  422. bool transAlpha = false;
  423. BitmapFormat format = RGB;
  424. // Strip off any 16 bit info
  425. //
  426. if (bit_depth == 16) {
  427. png_set_strip_16(png_ptr);
  428. }
  429. // Expand a transparency channel into a full alpha channel...
  430. //
  431. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
  432. png_set_expand(png_ptr);
  433. transAlpha = true;
  434. }
  435. if (color_type == PNG_COLOR_TYPE_PALETTE)
  436. {
  437. png_set_expand(png_ptr);
  438. format = transAlpha ? RGBA : RGB;
  439. }
  440. else if (color_type == PNG_COLOR_TYPE_GRAY)
  441. {
  442. png_set_expand(png_ptr);
  443. //png_set_gray_to_rgb(png_ptr);
  444. format = Alpha; //transAlpha ? RGBA : RGB;
  445. }
  446. else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  447. {
  448. png_set_expand(png_ptr);
  449. png_set_gray_to_rgb(png_ptr);
  450. format = RGBA;
  451. }
  452. else if (color_type == PNG_COLOR_TYPE_RGB)
  453. {
  454. format = transAlpha ? RGBA : RGB;
  455. png_set_expand(png_ptr);
  456. }
  457. else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
  458. {
  459. png_set_expand(png_ptr);
  460. format = RGBA;
  461. }
  462. // Update the info pointer with the result of the transformations
  463. // above...
  464. png_read_update_info(png_ptr, info_ptr);
  465. png_uint_32 rowBytes = png_get_rowbytes(png_ptr, info_ptr);
  466. if (format == RGB) {
  467. AssertFatal(rowBytes == width * 3,
  468. "Error, our rowbytes are incorrect for this transform... (3)");
  469. }
  470. else if (format == RGBA)
  471. {
  472. AssertFatal(rowBytes == width * 4,
  473. "Error, our rowbytes are incorrect for this transform... (4)");
  474. }
  475. // actually allocate the bitmap space...
  476. allocateBitmap(width, height,
  477. false, // don't extrude miplevels...
  478. format); // use determined format...
  479. // Set up the row pointers...
  480. AssertISV(height <= csgMaxRowPointers, "Error, cannot load pngs taller than 2048 pixels!");
  481. png_bytep* rowPointers = sRowPointers;
  482. U8* pBase = (U8*)getBits();
  483. for (U32 i = 0; i < height; i++)
  484. rowPointers[i] = pBase + (i * rowBytes);
  485. // And actually read the image!
  486. png_read_image(png_ptr, rowPointers);
  487. // We're outta here, destroy the png structs, and release the lock
  488. // as quickly as possible...
  489. //png_read_end(png_ptr, end_info);
  490. png_read_end(png_ptr, NULL);
  491. png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
  492. sg_pStream = NULL;
  493. // Ok, the image is read in, now we need to finish up the initialization,
  494. // which means: setting up the detailing members, init'ing the palette
  495. // key, etc...
  496. //
  497. // actually, all of that was handled by allocateBitmap, so we're outta here
  498. //
  499. FrameAllocator::setWaterMark(prevWaterMark);
  500. //
  501. //-Mat if all palleted images are to be converted, set mForce16bit
  502. if( color_type == PNG_COLOR_TYPE_PALETTE ) {
  503. sgForcePalletedPNGsTo16Bit = dAtob( Con::getVariable("$pref::iPhone::ForcePalletedPNGsTo16Bit") );
  504. if( sgForcePalletedPNGsTo16Bit ) {
  505. mForce16Bit = true;
  506. }
  507. }
  508. return true;
  509. }
  510. */