texture.cpp
上传用户:qccn516
上传日期:2013-05-02
资源大小:3382k
文件大小:28k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /* Texture
  2.  *
  3.  * Copyright (C) 2003-2004, Alexander Zaprjagaev <frustum@frustum.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <png.h>
  22. #include <setjmp.h>
  23. extern "C" {
  24. #include <jpeglib.h>
  25. }
  26. #include "engine.h"
  27. #include "texture.h"
  28. #ifdef _WIN32
  29. #pragma comment (lib,"libjpeg.lib")
  30. #pragma comment (lib,"libpng.lib")
  31. #pragma comment (lib,"zlib.lib")
  32. #endif
  33. /*
  34.  */
  35. Texture::Texture(int width,int height,GLuint target,int flag) : width(width), height(height), depth(1), target(target), flag(flag) {
  36. glGenTextures(1,&id);
  37. glBindTexture(target,id);
  38. if(flag & LUMINANCE) format = GL_LUMINANCE;
  39. else if(flag & LUMINANCE_ALPHA) format = GL_LUMINANCE_ALPHA;
  40. else if(flag & RGB) format = GL_RGB;
  41. else if(flag & RGBA) format = GL_RGBA;
  42. else fprintf(stderr,"Texture::Texture(): unknown formatn");
  43. GLuint type;
  44. GLuint internalformat;
  45. if(flag & FLOAT) {
  46. type = GL_FLOAT;
  47. if(format == GL_RGB) internalformat = GL_FLOAT_RGB_NV;
  48. else if(format == GL_RGBA) internalformat = GL_FLOAT_RGBA_NV;
  49. else {
  50. fprintf(stderr,"Texture::Texture(): FLOAT flag is accessible only for RGB or RGBA formatsn");
  51. return;
  52. }
  53. } else {
  54. type = GL_UNSIGNED_BYTE;
  55. internalformat = format;
  56. }
  57. if(flag & CLAMP) {
  58. glTexParameteri(target,GL_TEXTURE_WRAP_S,GL_CLAMP);
  59. glTexParameteri(target,GL_TEXTURE_WRAP_T,GL_CLAMP);
  60. glTexParameteri(target,GL_TEXTURE_WRAP_R,GL_CLAMP);
  61. } else if(flag & CLAMP_TO_EDGE) {
  62. glTexParameteri(target,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
  63. glTexParameteri(target,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
  64. glTexParameteri(target,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
  65. }
  66. if(flag & NEAREST) {
  67. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  68. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  69. } else if(flag & LINEAR) {
  70. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  71. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  72. } else if(flag & NEAREST_MIPMAP_NEAREST){
  73. glTexParameteri(target,GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
  74. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  75. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
  76. } else if(flag & LINEAR_MIPMAP_NEAREST) {
  77. glTexParameteri(target,GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
  78. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  79. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
  80. } else if(flag & LINEAR_MIPMAP_LINEAR) {
  81. glTexParameteri(target,GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
  82. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  83. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
  84. }
  85. if(flag & ANISOTROPY_1) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,1.0);
  86. else if(flag & ANISOTROPY_2) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,2.0);
  87. else if(flag & ANISOTROPY_4) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,4.0);
  88. else if(flag & ANISOTROPY_8) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,8.0);
  89. else if(flag & ANISOTROPY_16) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,16.0);
  90. if(target == TEXTURE_2D) glTexImage2D(target,0,internalformat,width,height,0,format,type,NULL);
  91. else if(target == TEXTURE_RECT) glTexImage2D(target,0,internalformat,width,height,0,format,type,NULL);
  92. else if(target == TEXTURE_CUBE) {
  93. glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X,0,internalformat,width,height,0,format,type,NULL);
  94. glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X,0,internalformat,width,height,0,format,type,NULL);
  95. glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y,0,internalformat,width,height,0,format,type,NULL);
  96. glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,0,internalformat,width,height,0,format,type,NULL);
  97. glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z,0,internalformat,width,height,0,format,type,NULL);
  98. glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,0,internalformat,width,height,0,format,type,NULL);
  99. }
  100. else if(target == TEXTURE_3D) glTexImage3D(target,0,internalformat,width,height,depth,0,format,type,NULL);
  101. }
  102. /*
  103.  */
  104. Texture::Texture(const char *name,GLuint target,int flag) {
  105. load(name,target,flag);
  106. }
  107. /*
  108.  */
  109. Texture::~Texture() {
  110. glDeleteTextures(1,&id);
  111. }
  112. /*
  113.  */
  114. void Texture::load(const char *name,GLuint target,int flag) {
  115. width = 0;
  116. height = 0;
  117. depth = 1;
  118. this->target = target;
  119. this->flag = flag;
  120. glGenTextures(1,&id);
  121. glBindTexture(target,id);
  122. if(flag & LUMINANCE) format = GL_LUMINANCE;
  123. else if(flag & LUMINANCE_ALPHA) format = GL_LUMINANCE_ALPHA;
  124. else if(flag & RGB) format = GL_RGB;
  125. else if(flag & RGBA) format = GL_RGBA;
  126. else fprintf(stderr,"Texture::Texture(): unknown formatn");
  127. if(flag & FLOAT) fprintf(stderr,"Texture::Texture(): FLOAT flag is not accessible for "%s" filen",name);
  128. if(flag & CLAMP) {
  129. glTexParameteri(target,GL_TEXTURE_WRAP_S,GL_CLAMP);
  130. glTexParameteri(target,GL_TEXTURE_WRAP_T,GL_CLAMP);
  131. glTexParameteri(target,GL_TEXTURE_WRAP_R,GL_CLAMP);
  132. } else if(flag & CLAMP_TO_EDGE) {
  133. glTexParameteri(target,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
  134. glTexParameteri(target,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
  135. glTexParameteri(target,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
  136. }
  137. if(flag & NEAREST) {
  138. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  139. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  140. } else if(flag & LINEAR) {
  141. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  142. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  143. } else if(flag & NEAREST_MIPMAP_NEAREST){
  144. glTexParameteri(target,GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
  145. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  146. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
  147. } else if(flag & LINEAR_MIPMAP_NEAREST) {
  148. glTexParameteri(target,GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
  149. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  150. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
  151. } else if(flag & LINEAR_MIPMAP_LINEAR) {
  152. glTexParameteri(target,GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
  153. glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  154. glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
  155. }
  156. if(flag & ANISOTROPY_2) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,2.0);
  157. else if(flag & ANISOTROPY_4) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,4.0);
  158. else if(flag & ANISOTROPY_8) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,8.0);
  159. else if(flag & ANISOTROPY_16) glTexParameterf(target,GL_TEXTURE_MAX_ANISOTROPY_EXT,16.0);
  160. if(target == TEXTURE_2D || target == TEXTURE_RECT) {
  161. unsigned char *data = load(name,width,height);
  162. if(data && format != GL_RGBA) {
  163. if(format == GL_LUMINANCE) data = rgba2luminance(data,width,height);
  164. else if(format == GL_LUMINANCE_ALPHA) data = rgba2luminance_alpha(data,width,height);
  165. else if(format == GL_RGB) data = rgba2rgb(data,width,height);
  166. }
  167. glTexImage2D(target,0,format,width,height,0,format,GL_UNSIGNED_BYTE,data);
  168. if(data) delete data;
  169. } else if(target == TEXTURE_CUBE) {
  170. GLuint targets[6] = {
  171. GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
  172. GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
  173. GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
  174. };
  175. char *suffix[6] = { "px", "nx", "py", "ny", "pz", "nz" };
  176. for(int i = 0; i < 6; i++) {
  177. char buf[1024];
  178. sprintf(buf,name,suffix[i]);
  179. unsigned char *data = load(buf,width,height);
  180. if(data && format != GL_RGBA) {
  181. if(format == GL_LUMINANCE) data = rgba2luminance(data,width,height);
  182. else if(format == GL_LUMINANCE_ALPHA) data = rgba2luminance_alpha(data,width,height);
  183. else if(format == GL_RGB) data = rgba2rgb(data,width,height);
  184. }
  185. glTexImage2D(targets[i],0,format,width,height,0,format,GL_UNSIGNED_BYTE,data);
  186. if(data) delete data;
  187. }
  188. } else if(target == TEXTURE_3D) {
  189. int fmt;
  190. unsigned char *data = load_3d(name,width,height,depth,fmt);
  191. if(fmt == LUMINANCE) format = GL_LUMINANCE;
  192. else if(fmt == LUMINANCE_ALPHA) format = GL_LUMINANCE_ALPHA;
  193. else if(fmt == RGBA) format = GL_RGBA;
  194. else format = GL_RGB;
  195. glTexImage3D(target,0,format,width,height,depth,0,format,GL_UNSIGNED_BYTE,data);
  196. if(data) delete data;
  197. }
  198. }
  199. /*
  200.  */
  201. void Texture::enable() {
  202. glEnable(target);
  203. }
  204. /*
  205.  */
  206. void Texture::disable() {
  207. glDisable(target);
  208. }
  209. /*
  210.  */
  211. void Texture::bind() {
  212. glBindTexture(target,id);
  213. }
  214. /*
  215.  */
  216. void Texture::copy(GLuint target) {
  217. if(target == 0) glCopyTexSubImage2D(this->target,0,0,0,0,0,width,height);
  218. else glCopyTexSubImage2D(target,0,0,0,0,0,width,height);
  219. }
  220. /*
  221.  */
  222. void Texture::render(float x0,float y0,float x1,float y1) {
  223. glBegin(GL_QUADS);
  224. if(target == TEXTURE_RECT) {
  225. glTexCoord2f(0,0);
  226. glVertex2f(x0,y0);
  227. glTexCoord2f(width,0);
  228. glVertex2f(x1,y0);
  229. glTexCoord2f(width,height);
  230. glVertex2f(x1,y1);
  231. glTexCoord2f(0,height);
  232. glVertex2f(x0,y1);
  233. } else {
  234. glTexCoord2f(0,0);
  235. glVertex2f(x0,y0);
  236. glTexCoord2f(1,0);
  237. glVertex2f(x1,y0);
  238. glTexCoord2f(1,1);
  239. glVertex2f(x1,y1);
  240. glTexCoord2f(0,1);
  241. glVertex2f(x0,y1);
  242. }
  243. glEnd();
  244. }
  245. /*****************************************************************************/
  246. /*                                                                           */
  247. /* IO functions                                                              */
  248. /*                                                                           */
  249. /*****************************************************************************/
  250. /* images
  251.  */
  252. unsigned char *Texture::load(const char *name,int &width,int &height) {
  253. char *ext = strrchr(name,'.');
  254. if(!ext) {
  255. fprintf(stderr,"Texture::load(): unknown format of "%s" file",name);
  256. return NULL;
  257. }
  258. unsigned char *data = NULL;
  259. if(!strcmp(ext,".tga")) data = load_tga(name,width,height);
  260. else if(!strcmp(ext,".png")) data = load_png(name,width,height);
  261. else if(!strcmp(ext,".jpg")) data = load_jpeg(name,width,height);
  262. else if(!strcmp(ext,".dds")) data = load_dds(name,width,height);
  263. else fprintf(stderr,"Texture::load(): unknown format of "%s" file",name);
  264. return data;
  265. }
  266. int Texture::save(const char *name,const unsigned char *data,int width,int height) {
  267. char *ext = strrchr(name,'.');
  268. if(!ext) {
  269. fprintf(stderr,"Texture::save(): unknown format of "%s" file",name);
  270. return 0;
  271. }
  272. int ret = 0;
  273. if(!strcmp(ext,".tga")) ret = save_tga(name,data,width,height);
  274. else if(!strcmp(ext,".jpg")) ret = save_jpeg(name,data,width,height,80);
  275. else fprintf(stderr,"Texture::save(): unknown format of "%s" file",name);
  276. return ret;
  277. }
  278. /*****************************************************************************/
  279. /*                                                                           */
  280. /* load and save                                                             */
  281. /*                                                                           */
  282. /*****************************************************************************/
  283. /* load tga image
  284.  * only for 24 and 32 bits per pixel
  285.  */
  286. unsigned char *Texture::load_tga(const char *name,int &width,int &height) {
  287. int i,j,k,l,components,size;
  288. unsigned char rep,*data,*buf,*ptr,info[18];
  289. FILE *file = fopen(name,"rb");
  290. if(!file) {
  291. fprintf(stderr,"Texture::load_tga(): error open "%s" filen",name);
  292. return NULL;
  293. }
  294. fread(&info,1,18,file);
  295. width = info[12] + info[13] * 256;
  296. height = info[14] + info[15] * 256;
  297. switch(info[16]) {
  298. case 32: components = 4; break;
  299. case 24: components = 3; break;
  300. default: fclose(file); return NULL;
  301. }
  302. size = width * height * components;
  303. buf = new unsigned char[size];
  304. data = new unsigned char[width * height * 4];
  305. if(!data || !buf) {
  306. fclose(file);
  307. return NULL;
  308. }
  309. fseek(file,info[0],SEEK_CUR);
  310. switch(info[2]) {
  311. case 2: fread(buf,1,size,file); break;
  312.         case 10:
  313. i = 0;
  314. ptr = buf;
  315. while(i < size) {
  316. fread(&rep,1,1,file);
  317. if(rep & 0x80) {
  318. rep ^= 0x80;
  319. fread(ptr,1,components,file);
  320. ptr += components;
  321. for(j = 0; j < rep * components; j++) {
  322. *ptr = *(ptr - components);
  323. ptr ++;
  324. }
  325. i += components * (rep + 1);
  326. } else {
  327. k = components * (rep + 1);
  328. fread(ptr,1,k,file);
  329. ptr += k;
  330. i += k;
  331. }
  332. }
  333. break;
  334. default:
  335. fclose(file);
  336. delete buf;
  337. delete data;
  338. return NULL;
  339. }
  340. for(i = 0, j = 0; i < size; i += components, j += 4) {
  341. data[j] = buf[i + 2];
  342. data[j + 1] = buf[i + 1];
  343. data[j + 2] = buf[i];
  344. if(components == 4) data[j + 3] = buf[i + 3];
  345. else data[j + 3] = 255;
  346. }
  347. if(!(info[17] & 0x20)) {
  348. for(j = 0, k = width * 4; j < height / 2; j++) {
  349. for(i = 0; i < width * 4; i++) {
  350. l = data[j * k + i];
  351. data[j * k + i] = data[(height - j - 1) * k + i];
  352. data[(height - j - 1) * k + i] = l;
  353. }
  354. }
  355. }
  356. fclose(file);
  357. delete buf;
  358. return data;
  359. }
  360. /* save tga image
  361.  */
  362. int Texture::save_tga(const char *name,const unsigned char *data,int width,int height) {
  363. int i,j;
  364. unsigned char *buf;
  365. FILE *file = fopen(name,"wb");
  366. if(!file) {
  367. fprintf(stderr,"Texture::save_tga(): error create "%s" filen",name);
  368. return 0;
  369. }
  370. buf = new unsigned char[18 + width * height * 4];
  371. memset(buf,0,18);
  372. buf[2] = 2;
  373. buf[12] = width % 256;
  374. buf[13] = width / 256;
  375. buf[14] = height % 256;
  376. buf[15] = height / 256;
  377. buf[16] = 32;
  378. buf[17] = 0x28;
  379. memcpy(buf + 18,data,width * height * 4);
  380. for(i = 18; i < 18 + width * height * 4; i += 4) {
  381. j = buf[i];
  382. buf[i] = buf[i + 2];
  383. buf[i + 2] = j;
  384. }
  385. fwrite(buf,1,18 + width * height * 4,file);
  386. fclose(file);
  387. delete buf;
  388. return 1;
  389. }
  390. /* load png image
  391.  */
  392. unsigned char *Texture::load_png(const char *name,int &width,int &height) {
  393. FILE *file = fopen(name,"rb");
  394. if(!file) {
  395. fprintf(stderr,"Texture::load_png(): error open "%s" filen",name);
  396. return NULL;
  397. }
  398. png_byte sig[8];
  399. fread(sig,8,1,file);
  400. if(!png_check_sig(sig,8)) {
  401. fprintf(stderr,"Texture::load_png(): wrong signature in "%s" filen",name);
  402. fclose(file);
  403. return NULL;
  404. }
  405. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
  406. if(!png_ptr) {
  407. fclose(file);
  408. return NULL;
  409. }
  410. png_infop info_ptr = png_create_info_struct(png_ptr);
  411. if(!info_ptr) {
  412. png_destroy_read_struct(&png_ptr,0,0);
  413. fclose(file);
  414. return NULL;
  415. }
  416. png_init_io(png_ptr,file);
  417. png_set_sig_bytes(png_ptr,8);
  418. png_read_info(png_ptr,info_ptr);
  419. unsigned long w,h;
  420. int bit_depth,color_type;
  421. png_get_IHDR(png_ptr,info_ptr,&w,&h,&bit_depth,&color_type,0,0,0);
  422. if(bit_depth == 16) png_set_strip_16(png_ptr);
  423. if(color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
  424. if(bit_depth < 8) png_set_expand(png_ptr);
  425. if(png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) png_set_expand(png_ptr);
  426. if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr);
  427. double gamma;
  428. if(png_get_gAMA(png_ptr,info_ptr,&gamma)) png_set_gamma(png_ptr,(double)2.2,gamma);
  429. png_read_update_info(png_ptr,info_ptr);
  430. png_get_IHDR(png_ptr,info_ptr,&w,&h,&bit_depth,&color_type,0,0,0);
  431. png_uint_32 row_bytes = png_get_rowbytes(png_ptr,info_ptr);
  432. png_uint_32 channels = png_get_channels(png_ptr,info_ptr);
  433. png_byte *img = new png_byte[row_bytes * h];
  434. png_byte **row = new png_byte*[h];
  435. for(int i = 0; i < (int)h; i++) row[i] = img + row_bytes * i;
  436. png_read_image(png_ptr,row);
  437. png_read_end(png_ptr,NULL);
  438. png_destroy_read_struct(&png_ptr,0,0);
  439. fclose(file);
  440. delete row;
  441. width = w;
  442. height = h;
  443. unsigned char *data = new unsigned char[width * height * 4];
  444. unsigned char *ptr = data;
  445. for(int i = 0; i < height; i++) {
  446. for(int j = 0; j < width; j++) {
  447. int k = row_bytes * i + j * channels;
  448. *ptr++ = img[k + 0];
  449. *ptr++ = img[k + 1];
  450. *ptr++ = img[k + 2];
  451. if(channels == 4) *ptr++ = img[k + 3];
  452. else *ptr++ = 255;
  453. }
  454. }
  455. delete img;
  456. return data;
  457. }
  458. /* load jpeg image
  459.  */
  460. struct my_error_mgr {
  461. struct jpeg_error_mgr pub;
  462. jmp_buf setjmp_buffer;
  463. };
  464. typedef struct my_error_mgr *my_error_ptr;
  465. static void my_error_exit(j_common_ptr cinfo) {
  466. my_error_ptr myerr = (my_error_ptr)cinfo->err;
  467. (*cinfo->err->output_message)(cinfo);
  468. longjmp(myerr->setjmp_buffer,1);
  469. }
  470. unsigned char *Texture::load_jpeg(const char *name,int &width,int &height) {
  471. struct jpeg_decompress_struct cinfo;
  472. struct my_error_mgr jerr;
  473. FILE *file;
  474. JSAMPARRAY buffer;
  475. int row_stride;
  476. long cont;
  477. JSAMPLE *data_buffer;
  478. int i,j;
  479. unsigned char *data;
  480. file = fopen(name,"rb");
  481. if(!file) {
  482. fprintf(stderr,"Texture::load_jpeg(): error open "%s" filen",name);
  483. return NULL;
  484. }
  485. cinfo.err = jpeg_std_error(&jerr.pub);
  486. jerr.pub.error_exit = my_error_exit;
  487. if(setjmp(jerr.setjmp_buffer)) {
  488. jpeg_destroy_decompress(&cinfo);
  489. fclose(file);
  490. return NULL;
  491. }
  492. jpeg_create_decompress(&cinfo);
  493. jpeg_stdio_src(&cinfo,file);
  494. jpeg_read_header(&cinfo,TRUE);
  495. jpeg_start_decompress(&cinfo);
  496. row_stride = cinfo.output_width * cinfo.output_components;
  497. buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);
  498. data_buffer = new JSAMPLE[cinfo.image_width * cinfo.image_height * cinfo.output_components];
  499. cont = 0;
  500. while(cinfo.output_scanline < cinfo.output_height) {
  501. jpeg_read_scanlines(&cinfo,buffer,1);
  502. memcpy(data_buffer + cinfo.image_width * cinfo.output_components * cont,buffer[0],row_stride);
  503. cont++;
  504. }
  505. jpeg_finish_decompress(&cinfo);
  506. jpeg_destroy_decompress(&cinfo);
  507. width = cinfo.image_width;
  508. height = cinfo.image_height;
  509. data = new unsigned char[width * height * 4];
  510. switch(cinfo.output_components) {
  511. case 1:
  512. for(i = 0, j = 0; i < width * height; i++, j += 4) {
  513. data[j] = data[j + 1] = data[j + 2] = data_buffer[i];
  514. data[j + 3] = 255;
  515. }
  516. break;
  517. case 3:
  518. for(i = 0, j = 0; i < width * height * 3; i += 3, j += 4) {
  519. data[j] = data_buffer[i];
  520. data[j + 1] = data_buffer[i + 1];
  521. data[j + 2] = data_buffer[i + 2];
  522. data[j + 3] = 255;
  523. }
  524. break;
  525. default:
  526. delete data;
  527. delete data_buffer;
  528. return NULL;
  529. }
  530. delete data_buffer;
  531. fclose(file);
  532. return data;
  533. }
  534. /* save jpeg image
  535.  */
  536. int Texture::save_jpeg(const char *name,const unsigned char *data,int width,int height,int quality) {
  537. struct jpeg_compress_struct cinfo;
  538. struct jpeg_error_mgr jerr;
  539. JSAMPROW row_pointer[1];
  540. int i,j,row_stride;
  541. unsigned char *data_buffer;
  542. FILE *file = fopen(name,"wb");
  543. if(!file) {
  544. fprintf(stderr,"Texture::load_jpeg(): error create "%s" filen",name);
  545. return 0;
  546. }
  547. data_buffer = new unsigned char[width * height * 3];
  548. for(i = 0, j = 0; i < width * height * 4; i += 4, j += 3) {
  549. data_buffer[j + 0] = data[i + 0];
  550. data_buffer[j + 1] = data[i + 1];
  551. data_buffer[j + 2] = data[i + 2];
  552. }
  553. cinfo.err = jpeg_std_error(&jerr);
  554. jpeg_create_compress(&cinfo);
  555. jpeg_stdio_dest(&cinfo,file);
  556. cinfo.image_width = width;
  557. cinfo.image_height = height;
  558. cinfo.input_components = 3;
  559. cinfo.in_color_space = JCS_RGB;
  560. jpeg_set_defaults(&cinfo);
  561. jpeg_set_quality(&cinfo,quality,TRUE);
  562. jpeg_start_compress(&cinfo,TRUE);
  563. row_stride = width * 3;
  564. while(cinfo.next_scanline < cinfo.image_height) {
  565. row_pointer[0] = &data_buffer[cinfo.next_scanline * row_stride];
  566. jpeg_write_scanlines(&cinfo,row_pointer,1);
  567. }
  568. jpeg_finish_compress(&cinfo);
  569. jpeg_destroy_compress(&cinfo);
  570. delete data_buffer;
  571. fclose(file);
  572. return 1;
  573. }
  574. /* load DDS image
  575.  */
  576. struct dds_colorkey {
  577. unsigned int dwColorSpaceLowValue;
  578. unsigned int dwColorSpaceHighValue;
  579. };
  580. struct dds_header {
  581. unsigned int magic;
  582. unsigned int dwSize;
  583. unsigned int dwFlags;
  584. unsigned int dwHeight;
  585. unsigned int dwWidth;
  586. long lPitch;
  587. unsigned int dwDepth;
  588. unsigned int dwMipMapCount;
  589. unsigned int dwAlphaBitDepth;
  590. unsigned int dwReserved;
  591. void *lpSurface;
  592. dds_colorkey ddckCKDestOverlay;
  593. dds_colorkey ddckCKDestBlt;
  594. dds_colorkey ddckCKSrcOverlay;
  595. dds_colorkey ddckCKSrcBlt;
  596. unsigned int dwPFSize;
  597. unsigned int dwPFFlags;
  598. unsigned int dwFourCC;
  599. unsigned int dwRGBBitCount;
  600. unsigned int dwRBitMask;
  601. unsigned int dwGBitMask;
  602. unsigned int dwBBitMask;
  603. unsigned int dwRGBAlphaBitMask;
  604. unsigned int dwCaps;
  605. unsigned int dwCaps2;
  606. unsigned int dwCaps3;
  607. unsigned int dwVolumeDepth;
  608. unsigned int dwTextureStage;
  609. };
  610. struct dds_color {
  611. unsigned char r;
  612. unsigned char g;
  613. unsigned char b;
  614. };
  615. enum {
  616. DDS_ERROR = -1,
  617. DDS_RGB,
  618. DDS_RGBA,
  619. DDS_DXT1,
  620. DDS_DXT2,
  621. DDS_DXT3,
  622. DDS_DXT4,
  623. DDS_DXT5
  624. };
  625. enum {
  626. DDPF_ALPHAPIXELS = 0x01,
  627. DDPF_FOURCC = 0x04,
  628. DDPF_RGB = 0x40,
  629. DDPF_RGBA = 0x41
  630. };
  631. unsigned char *Texture::load_dds(const char *name,int &width,int &height) {
  632. FILE *file = fopen(name,"rb");
  633. if(!file) {
  634. fprintf(stderr,"Texture::load_dds(): error open "%s" filen",name);
  635. return NULL;
  636. }
  637. dds_header header;
  638. fread(&header,sizeof(dds_header),1,file);
  639. if(header.magic != ('D' | 'D' << 8 | 'S' << 16 | ' ' << 24)) {
  640. fprintf(stderr,"Texture::load_dds(): wrong magic in "%s" filen",name);
  641. fclose(file);
  642. return NULL;
  643. }
  644. width = header.dwWidth;
  645. height = header.dwHeight;
  646. int format = DDS_ERROR;
  647. if(header.dwPFFlags & DDPF_FOURCC) {
  648. switch(header.dwFourCC) {
  649. case ('D' | 'X' << 8 | 'T' << 16 | '1' << 24): format = DDS_DXT1; break;
  650. case ('D' | 'X' << 8 | 'T' << 16 | '2' << 24): format = DDS_DXT2; break;
  651. case ('D' | 'X' << 8 | 'T' << 16 | '3' << 24): format = DDS_DXT3; break;
  652. case ('D' | 'X' << 8 | 'T' << 16 | '4' << 24): format = DDS_DXT4; break;
  653. case ('D' | 'X' << 8 | 'T' << 16 | '5' << 24): format = DDS_DXT5; break;
  654. }
  655. }
  656. else if(header.dwPFFlags == DDPF_RGB && header.dwRGBBitCount == 24) format = DDS_RGB;
  657. else if(header.dwPFFlags == DDPF_RGBA && header.dwRGBBitCount == 32) format = DDS_RGBA;
  658. else {
  659. fprintf(stderr,"Texture::load_dds(): unknown format of "%s" filen",name);
  660. fclose(file);
  661. return NULL;
  662. }
  663. if(format == DDS_DXT2 || format == DDS_DXT4) {
  664. fprintf(stderr,"Texture::load_dds(): DXT2 or DXT4 is not supported in "%s" filen",name);
  665. fclose(file);
  666. return NULL;
  667. }
  668. unsigned char *data = new unsigned char[width * height * 4];
  669. if(format == DDS_RGB) {
  670. unsigned char *buf = new unsigned char[width * height * 3];
  671. fread(buf,width * height * 3,1,file);
  672. unsigned char *src = buf;
  673. unsigned char *dest = data;
  674. for(int y = 0; y < height; y++) {
  675. for(int x = 0; x < width; x++) {
  676. *dest++ = *src++;
  677. *dest++ = *src++;
  678. *dest++ = *src++;
  679. *dest++ = 255;
  680. }
  681. }
  682. delete buf;
  683. } else if(format == DDS_RGBA) {
  684. unsigned char *buf = new unsigned char[width * height * 4];
  685. fread(buf,width * height * 4,1,file);
  686. unsigned char *src = buf;
  687. unsigned char *dest = data;
  688. for(int y = 0; y < height; y++) {
  689. for(int x = 0; x < width; x++) {
  690. *dest++ = *src++;
  691. *dest++ = *src++;
  692. *dest++ = *src++;
  693. *dest++ = *src++;
  694. }
  695. }
  696. delete buf;
  697. } else {
  698. unsigned char *buf = new unsigned char[width * height];
  699. unsigned char *src = buf;
  700. fread(buf,width * height,1,file);
  701. for(int y = 0; y < height; y += 4) {
  702. for(int x = 0; x < width; x += 4) {
  703. unsigned long long alpha = 0;
  704. unsigned int a0 = 0;
  705. unsigned int a1 = 0;
  706. if(format == DDS_DXT3) {
  707. alpha = *(unsigned long long*)src;
  708. src += 8;
  709. } else if(format == DDS_DXT5) {
  710. alpha=  (*(unsigned long long*)src) >> 16;
  711. a0 = src[0];
  712. a1 = src[1];
  713. src += 8;
  714. }
  715. unsigned int c0 = *(unsigned short*)(src + 0);
  716. unsigned int c1 = *(unsigned short*)(src + 2);
  717. src += 4;
  718. dds_color color[4];
  719. color[0].r = ((c0 >> 11) & 0x1f) << 3;
  720. color[0].g = ((c0 >> 5) & 0x3f) << 2;
  721. color[0].b = (c0 & 0x1f) << 3;
  722. color[1].r = ((c1 >> 11) & 0x1f) << 3;
  723. color[1].g = ((c1 >> 5) & 0x3f) << 2;
  724. color[1].b = (c1 & 0x1f) << 3;
  725. if(c0 > c1) {
  726. color[2].r = (color[0].r * 2 + color[1].r) / 3;
  727. color[2].g = (color[0].g * 2 + color[1].g) / 3;
  728. color[2].b = (color[0].b * 2 + color[1].b) / 3;
  729. color[3].r = (color[0].r + color[1].r * 2) / 3;
  730. color[3].g = (color[0].g + color[1].g * 2) / 3;
  731. color[3].b = (color[0].b + color[1].b * 2) / 3;
  732. } else {
  733. color[2].r = (color[0].r + color[1].r) / 2;
  734. color[2].g = (color[0].g + color[1].g) / 2;
  735. color[2].b = (color[0].b + color[1].b) / 2;
  736. color[3].r = 0;
  737. color[3].g = 0;
  738. color[3].b = 0;
  739. }
  740. for(int i = 0; i < 4; i++) {
  741. unsigned int index = *src++;
  742. unsigned char *dest = data + (width * (y + i) + x) * 4;
  743. for(int j = 0; j < 4; j++) {
  744. *dest++ = color[index & 0x03].r;
  745. *dest++ = color[index & 0x03].g;
  746. *dest++ = color[index & 0x03].b;
  747. if(format == DDS_DXT1) {
  748. *dest++ = ((index & 0x03) == 3 && c0 <= c1) ? 0 : 255;
  749. } else if(format == DDS_DXT3) {
  750. *dest++ = (alpha & 0x0f) << 4;
  751. alpha >>= 4;
  752. } else if(format == DDS_DXT5) {
  753. unsigned int a = alpha & 0x07;
  754. if(a == 0) *dest++ = a0;
  755. else if(a == 1) *dest++ = a1;
  756. else if(a0 > a1) *dest++ = ((8 - a) * a0 + (a - 1) * a1) / 7;
  757. else if(a > 5) *dest++ = (a == 6) ? 0 : 255;
  758. else *dest++ = ((6 - a) * a0 + (a - 1) * a1) / 5;
  759. alpha >>= 3;
  760. } else *dest++ = 255;
  761. index >>= 2;
  762. }
  763. }
  764. }
  765. }
  766. delete buf;
  767. }
  768. fclose(file);
  769. return data;
  770. }
  771. /*****************************************************************************/
  772. /*                                                                           */
  773. /* converters                                                                */
  774. /*                                                                           */
  775. /*****************************************************************************/
  776. unsigned char *Texture::rgba2rgb(unsigned char *data,int width,int height) {
  777. unsigned char *dest = new unsigned char[width * height * 3];
  778. unsigned char *d = dest;
  779. unsigned char *s = data;
  780. for(int i = 0; i < width * height; i++) {
  781. *d++ = *s++;
  782. *d++ = *s++;
  783. *d++ = *s++;
  784. s++;
  785. }
  786. delete data;
  787. return dest;
  788. }
  789. unsigned char *Texture::rgba2luminance(unsigned char *data,int width,int height) {
  790. unsigned char *dest = new unsigned char[width * height];
  791. unsigned char *d = dest;
  792. unsigned char *s = data;
  793. for(int i = 0; i < width * height; i++) {
  794. *d++ = *s++;
  795. s += 3;
  796. }
  797. delete data;
  798. return dest;
  799. }
  800. unsigned char *Texture::rgba2luminance_alpha(unsigned char *data,int width,int height) {
  801. unsigned char *dest = new unsigned char[width * height * 2];
  802. unsigned char *d = dest;
  803. unsigned char *s = data;
  804. for(int i = 0; i < width * height; i++) {
  805. *d++ = *s++;
  806. s += 2;
  807. *d++ = *s++;
  808. }
  809. delete data;
  810. return dest;
  811. }
  812. /*****************************************************************************/
  813. /*                                                                           */
  814. /* 3d textures                                                               */
  815. /*                                                                           */
  816. /*****************************************************************************/
  817. unsigned char *Texture::load_3d(const char *name,int &width,int &height,int &depth,int &format) {
  818. FILE *file = fopen(name,"rb");
  819. if(!file) {
  820. fprintf(stderr,"Texture::load_3d(): error open "%s" filen",name);
  821. return NULL;
  822. }
  823. int magic;
  824. fread(&magic,sizeof(int),1,file);
  825. if(magic != ('3' | 'D' << 8 | 'T' << 16 | 'X' << 24)) {
  826. fprintf(stderr,"Texture::load_3d(): wrong magic in "%s" filen",name);
  827. fclose(file);
  828. return NULL;
  829. }
  830. fread(&width,sizeof(int),1,file);
  831. fread(&height,sizeof(int),1,file);
  832. fread(&depth,sizeof(int),1,file);
  833. fread(&format,sizeof(int),1,file);
  834. int size = width * height * depth;
  835. if(format == LUMINANCE) size *= 1;
  836. else if(format == LUMINANCE_ALPHA) size *= 2;
  837. else if(format == RGB) size *= 3;
  838. else if(format == RGBA) size *= 4;
  839. else {
  840. fprintf(stderr,"Texture::load_3d(): unknown format of "%s" filen",name);
  841. fclose(file);
  842. return NULL;
  843. }
  844. unsigned char *data = new unsigned char[size];
  845. fread(data,sizeof(unsigned char),size,file);
  846. fclose(file);
  847. return data;
  848. }
  849. /*
  850.  */
  851. int Texture::save_3d(const char *name,const unsigned char *data,int width,int height,int depth,int format) {
  852. FILE *file = fopen(name,"wb");
  853. if(!file) {
  854. fprintf(stderr,"Texture::save_3d(): error create "%s" filen",name);
  855. return 0;
  856. }
  857. int magic = ('3' | 'D' << 8 | 'T' << 16 | 'X' << 24);
  858. fwrite(&magic,sizeof(int),1,file);
  859. fwrite(&width,sizeof(int),1,file);
  860. fwrite(&height,sizeof(int),1,file);
  861. fwrite(&depth,sizeof(int),1,file);
  862. fwrite(&format,sizeof(int),1,file);
  863. int size = width * height * depth;
  864. if(format == LUMINANCE) size *= 1;
  865. else if(format == LUMINANCE_ALPHA) size *= 2;
  866. else if(format == RGB) size *= 3;
  867. else if(format == RGBA) size *= 4;
  868. else fprintf(stderr,"Texture::save_3d(): unknown formatn");
  869. fwrite(data,sizeof(unsigned char),size,file);
  870. fclose(file);
  871. return 1;
  872. }