Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vsimage.cpp
Go to the documentation of this file.
1 #include "vsimage.h"
2 
3 #if defined (__APPLE__) || defined (MACOSX)
4  #include <GLUT/glut.h>
5  #include <OpenGL/glext.h>
6 #else
7  #include <GL/glut.h>
8  #include <GL/glext.h>
9 #endif
10 
11 #include "cmd/unit_generic.h"
12 
13 #include "vsfilesystem.h"
14 #include "vs_globals.h"
15 #include <png.h>
16 #include "posh.h"
17 
18 #ifndef png_jmpbuf
19 # define png_jmpbuf( png_ptr ) ( (png_ptr)->jmpbuf )
20 #endif
21 
22 #if defined (_WIN32) && !defined (__CYGWIN__)
23 
24 #ifndef HAVE_BOOLEAN
25 #define HAVE_BOOLEAN
26 #define FALSE 0
27 #define TRUE 1
28 typedef unsigned char boolean;
29 #endif
30 
31 #endif
32 
33 #ifndef DDS_CUBEMAP
34 #define DDS_CUBEMAP 0x00000200L
35 #define DDS_CUBEMAP_POSITIVEX 0x00000400L
36 #define DDS_CUBEMAP_NEGATIVEX 0x00000800L
37 #define DDS_CUBEMAP_POSITIVEY 0x00001000L
38 #define DDS_CUBEMAP_NEGATIVEY 0x00002000L
39 #define DDS_CUBEMAP_POSITIVEZ 0x00004000L
40 #define DDS_CUBEMAP_NEGATIVEZ 0x00008000L
41 #define DDS_CUBEMAP_ALLFACES \
42  (DDS_CUBEMAP_POSITIVEX|DDS_CUBEMAP_NEGATIVEX \
43  |DDS_CUBEMAP_POSITIVEY|DDS_CUBEMAP_NEGATIVEY \
44  |DDS_CUBEMAP_POSITIVEZ|DDS_CUBEMAP_NEGATIVEZ)
45 #endif
46 
47 #include "gfx/jpeg_memory.h"
48 #include <iostream>
49 
54 //using VSFileSystem::img_file;
55 
57 int PNG_HAS_COLOR = 2;
58 int PNG_HAS_ALPHA = 4;
59 
60 LOCALCONST_DEF( VSImage, int, SIZEOF_BITMAPFILEHEADER, sizeof (WORD)+sizeof (DWORD)+sizeof (WORD)+sizeof (WORD)
61  +sizeof (DWORD) )
63  *sizeof (DWORD)+2*sizeof (LONG)+2*sizeof (DWORD) )
64 LOCALCONST_DEF( VSImage, int, SIZEOF_RGBQUAD, sizeof (BYTE)*4 ) VSImage::VSImage()
65 {
66  this->img_depth = 8;
67  this->img_color_type = 8;
68  this->sizeY = 1;
69  this->sizeX = 1;
70  this->Init();
71  this->mode = _24BIT;
72 }
73 
74 void VSImage::Init()
75 {
76  this->tt = NULL;
77  this->img_type = Unrecognized;
78  //this->tex->palette = NULL;
79  this->strip_16 = false;
80 }
81 
82 void VSImage::Init( VSFile *f, textureTransform *t, bool strip, VSFile *f2 )
83 {
84  assert( f != NULL );
85 
86  this->Init();
87 
88  this->img_file = f;
89  this->img_file2 = f2;
90  this->tt = t;
91  this->strip_16 = strip;
92 }
93 
94 VSImage::VSImage( VSFile *f, textureTransform *t, bool strip, VSFile *f2 )
95 {
96  this->mode = _24BIT;
97  this->Init( f, t, strip, f2 );
98 }
99 
101 {
102  //img_file? and tt should not be deleted since they are passed as args to the class
103 }
104 
105 unsigned char* VSImage::ReadImage( VSFile *f, textureTransform *t, bool strip, VSFile *f2 )
106 {
107  try {
108  this->Init( f, t, strip, f2 );
109 
110  unsigned char *ret = NULL;
111  CheckFormat( img_file );
112  switch (this->img_type)
113  {
114  case DdsImage:
115  ret = this->ReadDDS();
116  break;
117  case PngImage:
118  ret = this->ReadPNG();
119  break;
120  case JpegImage:
121  ret = this->ReadJPEG();
122  break;
123  case BmpImage:
124  ret = this->ReadBMP();
125  break;
126  default:
127  vs_dprintf( 1, "%s\n", img_file->GetFilename().c_str() );
128  ret = NULL;
129  }
130  return ret;
131  }
132  catch (...) {
133  //ReadXXX() already handles exceptions. But, if any exception remains unhandled,
134  //this handler will perform a dirty abortion (reclaims no memory, but doesn't crash at least)
135  return NULL;
136  }
137 }
138 
139 VSError VSImage::CheckPNGSignature( VSFile *file )
140 {
141  //Do standard reading of the file
142  unsigned char sig[8];
143  file->Begin();
144  file->Read( sig, 8 );
145  if ( png_sig_cmp( sig, 0, 8 ) )
146  return BadFormat;
147  else
148  return Ok;
149 }
150 
151 VSError VSImage::CheckJPEGSignature( VSFile *file )
152 {
153  VSError ret = Ok;
154 
155  //First 4 aren't known to me
156  //Next 2 bytes is length
157  //Next 5 are JFIF\0
158  //Next 2 are version numbers
159  char sig[13];
160  file->Begin();
161  file->Read( sig, 13 );
162  /*
163  * for( int i=0; i<13; i++)
164  * std::cerr<<sig[i]<<" ";
165  * std::cerr<<std::endl;
166  */
167  if ( strncmp( sig+6, "JFIF", 4 ) )
168  ret = BadFormat;
169  file->Begin();
170  return ret;
171 }
172 
173 VSError VSImage::CheckBMPSignature( VSFile *file )
174 {
175  VSError ret = Ok;
176 
177  char head1;
178  char head2;
179  file->Begin();
180  file->Read( &head1, 1 );
181  file->Read( &head2, 1 );
182  if (toupper( head1 ) != 'B' || toupper( head2 ) != 'M')
183  ret = BadFormat;
184  file->Begin();
185 
186  return ret;
187 }
188 
189 VSError VSImage::CheckDDSSignature( VSFile *file )
190 {
191  VSError ret = Ok;
192  char ddsfile[5];
193  file->Begin();
194  file->Read( &ddsfile, 4 );
195  if (strncmp( ddsfile, "DDS ", 4 ) != 0)
196  ret = BadFormat;
197  file->Begin();
198  return ret;
199 }
200 
201 void VSImage::CheckFormat( VSFile *file )
202 {
203  if (this->CheckDDSSignature( file ) == Ok) {
204  vs_dprintf(3,"\tFound a DDS file\n");
205  this->img_type = DdsImage;
206  return;
207  }
208  if (this->CheckPNGSignature( file ) == Ok) {
209  vs_dprintf(3,"\tFound a PNG file\n");
210  this->img_type = PngImage;
211  return;
212  }
213  if (this->CheckBMPSignature( file ) == Ok) {
214  vs_dprintf(3,"\tFound a BMP file\n");
215  this->img_type = BmpImage;
216  return;
217  }
218  if (this->CheckJPEGSignature( file ) == Ok) {
219  vs_dprintf(3,"\tFound a JPEG file\n");
220  this->img_type = JpegImage;
221  return;
222  }
223 }
224 
225 void PngReadFunc( png_struct *Png, png_bytep buf, png_size_t size )
226 {
227  vs_dprintf(3,"Preparing to copy %u bytes from PngFileBuffer\n");
228  TPngFileBuffer *PngFileBuffer = (TPngFileBuffer*) png_get_io_ptr( Png );
229  memcpy( buf, PngFileBuffer->Buffer+PngFileBuffer->Pos, size );
230  PngFileBuffer->Pos += size;
231 }
232 
233 /* We can't write in volumes yet so this is useless now
234  * void PngWriteFunc(png_struct *Png, png_bytep buf, png_size_t size)
235  * {
236  * std::cerr<<"PNG DEBUG : preparing to write "<<size<<" bytes from PngFileBuffer"<<std::endl;
237  * }
238  */
239 
240 static void png_cexcept_error( png_structp png_ptr, png_const_charp msg )
241 {
242  if (png_ptr)
243  ;
244 #ifndef PNG_NO_CONSOLE_IO
245  vs_dprintf(1,"libpng error: %s\n",msg);
246 #endif
247 }
248 
249 unsigned char* VSImage::ReadPNG()
250 {
251  png_bytepp row_pointers = NULL;
252  unsigned char *image = NULL;
253 
254  try {
255  TPngFileBuffer PngFileBuffer = {NULL, 0};
256  palette = NULL;
257  png_structp png_ptr;
258  png_infop info_ptr;
259  int interlace_type;
260 
261  img_file->Begin();
262  if ( !CheckPNGSignature( img_file ) ) {
263  vs_dprintf(1,"VSImage::ReadPNG() ERROR : NOT A PNG FILE\n");
264  vs_dprintf( 1, "%s\n", img_file->GetFilename().c_str() );
265  throw (1);
266  }
267  //Go after sig since we already checked it
268  //Only when reading from a buffer otherwise CheckPNGSignature already did the work
269  if ( img_file->UseVolume() ) {
270  PngFileBuffer.Buffer = img_file->get_pk3_data();
271  PngFileBuffer.Pos = 8;
272  }
273  png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr) png_cexcept_error, (png_error_ptr) NULL );
274  if (png_ptr == NULL) {
275  vs_dprintf( 1, "%s\n", img_file->GetFilename().c_str() );
276  throw (1);
277  }
278  info_ptr = png_create_info_struct( png_ptr );
279  if (info_ptr == NULL) {
280  png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
281  vs_dprintf(1,"VSImage ERROR : PNG info_ptr == NULL !!!\n");
282  vs_dprintf( 1, "%s\n", img_file->GetFilename().c_str() );
283  throw (1);
284  }
285  if ( setjmp( png_jmpbuf( png_ptr ) ) ) {
286  /* Free all of the memory associated with the png_ptr and info_ptr */
287  png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
288  /* If we get here, we had a problem reading the file */
289  vs_dprintf(1, "VSImage ERROR : problem reading file/buffer -> setjmp !!!\n");
290  vs_dprintf( 1, "%s\n", img_file->GetFilename().c_str() );
291  throw (1);
292  }
293  if ( !img_file->UseVolume() )
294  png_init_io( png_ptr, img_file->GetFP() );
295  else
296  png_set_read_fn( png_ptr, (png_voidp)&PngFileBuffer, (png_rw_ptr) PngReadFunc );
297  png_set_sig_bytes( png_ptr, 8 );
298  vs_dprintf(3, "Loading Done. Decompressing\n");
299  png_read_info( png_ptr, info_ptr ); /* read all PNG info up to image data */
300  this->sizeX = 1;
301  this->sizeY = 1;
302  this->img_depth = 8;
303  this->img_nmips = 0;
304  this->img_sides = SIDE_SINGLE;
305 
306  png_get_IHDR( png_ptr,
307  info_ptr,
308  (png_uint_32*) &this->sizeX,
309  (png_uint_32*) &this->sizeY,
310  &this->img_depth,
311  &this->img_color_type,
312  &interlace_type,
313  NULL,
314  NULL );
315  vs_dprintf(3, "1. Loading a PNG file: width = %u , height = %u , depth = %u , img color = %u , intelace = %u \n", sizeX, sizeY, img_depth, img_color_type, interlace_type);
316 # if __BYTE_ORDER != __BIG_ENDIAN
317  if (this->img_depth == 16)
318  png_set_swap( png_ptr );
319 #endif
320  if (this->img_depth == 16 && strip_16)
321  png_set_strip_16( png_ptr );
322  if (strip_16 && this->img_color_type == PNG_COLOR_TYPE_PALETTE)
323  png_set_palette_to_rgb( png_ptr );
324  if (this->img_color_type == PNG_COLOR_TYPE_GRAY && this->img_depth < 8) {
325  png_set_expand_gray_1_2_4_to_8( png_ptr );
326  }
327  png_set_expand( png_ptr );
328  png_read_update_info( png_ptr, info_ptr );
329  this->sizeX = 1;
330  this->sizeY = 1;
331  this->img_depth = 8;
332  png_get_IHDR( png_ptr,
333  info_ptr,
334  (png_uint_32*) &this->sizeX,
335  (png_uint_32*) &this->sizeY,
336  &this->img_depth,
337  &this->img_color_type,
338  &interlace_type,
339  NULL,
340  NULL );
341  vs_dprintf(3, "2. Loading a PNG file : width = %u , height = %u , depth = %u , img_color = %u , interlace = %u\n",sizeX, sizeY, img_depth, img_color_type, interlace_type);
342  if (img_depth != 16)
343  img_depth = 8;
344  row_pointers = (unsigned char**) malloc( sizeof (unsigned char*)*this->sizeY );
345  int numchan = 1;
346  if (this->img_color_type&PNG_COLOR_MASK_COLOR)
347  numchan = 3;
348  if (this->img_color_type&PNG_COLOR_MASK_PALETTE)
349  numchan = 1;
350  if (this->img_color_type&PNG_COLOR_MASK_ALPHA)
351  numchan++;
352  if (numchan == 1)
353  mode = _8BIT;
354  else if (numchan == 3)
355  mode = _24BIT;
356  else
357  mode = _24BITRGBA;
358  unsigned long stride = numchan*sizeof (unsigned char)*this->img_depth/8;
359  vs_dprintf(3, "3. Allocating image buffer of size = %u \n",(stride*sizeX*sizeY));
360  image = (unsigned char*) malloc( stride*this->sizeX*this->sizeY );
361  for (unsigned int i = 0; i < this->sizeY; i++)
362  row_pointers[i] = &image[i*stride*this->sizeX];
363  png_read_image( png_ptr, row_pointers );
364  unsigned char *result;
365  if (tt) {
366  vs_dprintf(3, "4. Doing a transformation \n");
367  result = (*tt)(this->img_depth, this->img_color_type, this->sizeX, this->sizeY, row_pointers);
368  free( image );
369  image = NULL;
370  } else {
371  result = image;
372  }
373  free( row_pointers );
374  row_pointers = NULL;
375  png_read_end( png_ptr, info_ptr );
376  png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
377  png_ptr = NULL;
378  info_ptr = NULL;
379  vs_dprintf(3, "Decompressing Done.\n");
380  if (result)
381  this->AllocatePalette();
382  return result;
383  }
384  catch (...) {
385  if (image)
386  free( image );
387  image = NULL;
388  if (row_pointers)
389  free( row_pointers );
390  row_pointers = NULL;
391  return NULL;
392  }
393 }
394 
396 {
397  struct jpeg_error_mgr pub; //"public" fields
398  jmp_buf setjmp_buffer; //for return to caller
399 };
400 
401 METHODDEF( void ) my_error_exit( j_common_ptr cinfo )
402 {
403  //cinfo->err really points to a my_error_mgr struct, so coerce pointer
404  my_error_mgr *myerr = (my_error_mgr*) cinfo->err;
405 
406  //Always display the message.
407  //We could postpone this until after returning, if we chose.
408  (*cinfo->err->output_message)( cinfo );
409 
410  //Return control to the setjmp point
411  longjmp( myerr->setjmp_buffer, 1 );
412 }
413 
414 unsigned char* VSImage::ReadJPEG()
415 {
416  unsigned char *image = NULL;
417  JSAMPARRAY row_pointers = NULL; //Output row buffer
418 
419  try {
420  this->img_depth = 8;
421  jpeg_decompress_struct cinfo;
422 
423  my_error_mgr jerr;
424 
425  cinfo.err = jpeg_std_error( &jerr.pub );
426  jerr.pub.error_exit = my_error_exit;
427  if ( setjmp( jerr.setjmp_buffer ) ) {
428  //If we get here, the JPEG code has signaled an error.
429  //We need to clean up the JPEG object, and return.
430  jpeg_destroy_decompress( &cinfo );
431  vs_dprintf(1 ,"VSImage ERROR : error reading jpg file\n");
432  vs_dprintf( 1, "%s\n", img_file->GetFilename().c_str() );
433  throw (1);
434  }
435  jpeg_create_decompress( &cinfo );
436  if ( !img_file->UseVolume() )
437  jpeg_stdio_src( (j_decompress_ptr)&cinfo, img_file->GetFP() );
438  else
439  jpeg_memory_src( &cinfo, (unsigned char*) img_file->get_pk3_data(), img_file->Size() );
440  (void) jpeg_read_header( &cinfo, TRUE );
441  this->sizeX = cinfo.image_width;
442  this->sizeY = cinfo.image_height;
443  this->img_nmips = 0;
444  this->img_sides = SIDE_SINGLE;
445 
446  (void) jpeg_start_decompress( &cinfo );
447 
448  this->img_color_type = PNG_COLOR_TYPE_RGB;
449  if (cinfo.output_components == 1)
450  this->img_color_type = PNG_COLOR_TYPE_GRAY;
451  else if (cinfo.output_components == 4)
452  this->img_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
453  else if (cinfo.output_components == 2)
454  this->img_color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
455  switch (this->img_color_type)
456  {
457  case PNG_COLOR_TYPE_RGB:
458  this->mode = _24BIT;
459  break;
460  case PNG_COLOR_TYPE_RGB_ALPHA:
461  this->mode = _24BITRGBA;
462  break;
463  case PNG_COLOR_TYPE_GRAY:
464  this->mode = _8BIT;
465  break;
466  case PNG_COLOR_TYPE_GRAY_ALPHA:
467  this->mode = _8BIT;
468  break;
469  }
470  vs_dprintf(3, "1. Loading a JPEG file : width= %u , height = %u , img_color = %u \n",sizeX, sizeY, img_color_type);
471  row_pointers = (unsigned char**) malloc( sizeof (unsigned char*)*cinfo.image_height );
472 
473  this->img_depth = 8;
474  int numchan = cinfo.output_components;
475 
476  unsigned long stride = numchan*sizeof (unsigned char)*this->img_depth/8;
477  image = (unsigned char*) malloc( stride*cinfo.image_width*cinfo.image_height );
478  for (unsigned int i = 0; i < cinfo.image_height; i++)
479  row_pointers[i] = &image[i*stride*cinfo.image_width];
480  unsigned int count = 0;
481  while (count < this->sizeY)
482  count += jpeg_read_scanlines( &cinfo, &(row_pointers[count]), this->sizeY-count );
483  (void) jpeg_finish_decompress( &cinfo );
484  jpeg_destroy_decompress( &cinfo );
485 
486  unsigned char *result = image;
487  if (tt) {
488  result = (*tt)(this->img_depth, this->img_color_type, this->sizeX, this->sizeY, row_pointers);
489  free( image );
490  image = NULL;
491  }
492  free( row_pointers );
493  row_pointers = NULL;
494  if (result)
495  this->AllocatePalette();
496  return result;
497  }
498  catch (...) {
499  if (image) free( image );
500  image = NULL;
501  if (row_pointers) free( row_pointers );
502  row_pointers = NULL;
503  return NULL;
504  }
505 }
506 
507 unsigned char* VSImage::ReadBMP()
508 {
509  unsigned char *data = NULL;
510  unsigned char *cdata = NULL;
511  unsigned char *adata = NULL;
512 
513  try {
514  if (CheckBMPSignature( img_file ) != Ok) {
515  vs_dprintf(1, "VSImage ERROR : BMP signature check failed : this should not happen !!!\n");
516  vs_dprintf( 1,"%s\n", img_file->GetFilename().c_str() );
517  throw (1);
518  }
519  //seek back to beginning
520  img_file->GoTo( SIZEOF_BITMAPFILEHEADER );
521  //long temp;
522  BITMAPINFOHEADER info;
523  img_file->Read( &info, SIZEOF_BITMAPINFOHEADER );
524  this->sizeX = le32_to_cpu( info.biWidth );
525  this->sizeY = le32_to_cpu( info.biHeight );
526  this->img_sides = SIDE_SINGLE;
527  this->img_nmips = 0;
528  /*
529  * if (img_file2!=NULL)
530  * {
531  * img_file2->GoTo(SIZEOF_BITMAPFILEHEADER);
532  *
533  * img_file2->Read(&info1,SIZEOF_BITMAPINFOHEADER);
534  * if (tex->sizeX != (unsigned int) le32_to_cpu(info1.biWidth)||tex->sizeY!=(unsigned int)le32_to_cpu(info1.biHeight))
535  * {
536  * return NULL;
537  * }
538  * RGBQUAD ptemp1;
539  * if (le16_to_cpu(info1.biBitCount) == 8)
540  * {
541  * for (int i=0; i<256; i++)
542  * img_file2->Read(&ptemp1, sizeof(RGBQUAD)); //get rid of the palette for a b&w greyscale alphamap
543  *
544  * }
545  * }
546  */
547  if (le16_to_cpu( info.biBitCount ) == 24) {
548  mode = _24BIT; //Someone said _24BIT isn't supported by most cards, but PNG and JPEG use it widely without problems, so it must be untrue...
549  if ( img_file2 && img_file2->Valid() )
550  mode = _24BITRGBA;
551  int ncomp = ( (mode == _24BIT) ? 3 : 4 );
552  unsigned int cstride = ( (sizeof (unsigned char)*3*this->sizeX)+3 )&~3; //BMP rows must be aligned to 32 bits
553  unsigned int astride = ( (sizeof (unsigned char)*this->sizeX)+3 )&~3; //BMP rows must be aligned to 32 bits
554  unsigned int stride = (sizeof (unsigned char)*ncomp*this->sizeX);
555  data = (unsigned char*) malloc( stride*this->sizeY );
556  if (data == NULL) return NULL;
557  if (mode != _24BIT) {
558  cdata = (unsigned char*) malloc( cstride );
559  adata = (unsigned char*) malloc( astride );
560  if ( (cdata == NULL) || (adata == NULL) ) throw ("memory");
561  unsigned char *row = data+(this->sizeY-1)*stride;
562  for (unsigned int i = 0; i < this->sizeY; i++, row -= stride) {
563  img_file->Read( cdata, cstride );
564  img_file2->Read( adata, astride );
565  unsigned char *cpix = cdata, *apix = adata, *pix = row;
566  for (unsigned int j = 0; j < this->sizeX; j++, cpix += 3, apix++, pix += 4) {
567  pix[0] = cpix[2];
568  pix[1] = cpix[1];
569  pix[2] = cpix[0];
570  pix[3] = apix[0];
571  }
572  }
573  free( cdata );
574  cdata = NULL;
575  free( adata );
576  adata = NULL;
577  } else {
578  unsigned char *row = data+(this->sizeY-1)*stride;
579  unsigned long dummy;
580  for (unsigned int i = 0; i < this->sizeY; i++, row -= stride) {
581  img_file->Read( row, stride );
582  if (cstride > stride) {
583  assert( cstride-stride < sizeof (dummy) );
584  img_file->Read( &dummy, cstride-stride );
585  }
586  unsigned char *pix = row;
587  for (unsigned int j = 0; j < this->sizeX; j++, pix += 3) {
588  unsigned char apix = pix[0];
589  pix[0] = pix[2];
590  pix[2] = apix;
591  }
592  }
593  }
594  } else if (le16_to_cpu( info.biBitCount ) == 8) {
595  mode = _8BIT;
596  data = NULL;
597  data = (unsigned char*) malloc( sizeof (unsigned char)*sizeY*sizeX );
598  this->palette = (unsigned char*) malloc( sizeof (unsigned char)*(256*4+1) );
599  memset( this->palette, 0, (256*4+1)*sizeof (unsigned char) );
600  unsigned char *paltemp = this->palette;
601  unsigned char ctemp;
602  for (int palcount = 0; palcount < 256; palcount++) {
603  img_file->Read( paltemp, SIZEOF_RGBQUAD );
604  ctemp = paltemp[0];
605  paltemp[0] = paltemp[2];
606  paltemp[2] = ctemp;
607  paltemp += 4; //pal size
608  }
609  if (!data)
610  return NULL;
611  for (int i = sizeY-1; i >= 0; i--)
612  for (unsigned int j = 0; j < sizeX; j++)
613  img_file->Read( data+j+i*sizeX, sizeof (unsigned char) );
614  }
615  return data;
616  }
617  catch (...) {
618  if (cdata) free( cdata );
619  cdata = NULL;
620  if (adata) free( adata );
621  adata = NULL;
622  if (data) free( data );
623  data = NULL;
624  return NULL;
625  }
626  ;
627 }
628 
629 #define IS_POT( x ) ( !( (x)& ( (x)-1 ) ) )
630 
631 unsigned char* VSImage::ReadDDS()
632 {
633  ddsHeader header;
634  unsigned int internal = GL_NONE, type = GL_RGB;
635  int blockSize = 16;
636  unsigned char *s = NULL;
637  unsigned int inputSize = 0;
638  int width = 0;
639  int height = 0;
640  try {
641  //Skip what we already know.
642  img_file->GoTo( 4 );
643  //Read in bytes to header. Not sure if just reading to struct is endian-safe.
644  char ibuffer[4];
645  img_file->Read( ibuffer, 4 );
646  header.size = POSH_ReadU32FromLittle( ibuffer );
647  img_file->Read( ibuffer, 4 );
648  header.flags = POSH_ReadU32FromLittle( ibuffer );
649  img_file->Read( ibuffer, 4 );
650  header.height = POSH_ReadU32FromLittle( ibuffer );
651  img_file->Read( ibuffer, 4 );
652  header.width = POSH_ReadU32FromLittle( ibuffer );
653  img_file->Read( ibuffer, 4 );
654  header.linsize = POSH_ReadU32FromLittle( ibuffer );
655  img_file->Read( ibuffer, 4 );
656  header.depth = POSH_ReadU32FromLittle( ibuffer );
657  img_file->Read( ibuffer, 4 );
658  header.nmips = POSH_ReadU32FromLittle( ibuffer );
659  img_file->GoTo( 84 );
660  img_file->Read( header.pixelFormat.fourcc, 4 );
661  img_file->Read( ibuffer, 4 );
662  header.pixelFormat.bpp = POSH_ReadU32FromLittle( ibuffer );
663  img_file->GoTo( 108 );
664  img_file->Read( ibuffer, 4 );
665  header.dcaps1 = POSH_ReadU32FromLittle( ibuffer );
666  img_file->Read( ibuffer, 4 );
667  header.dcaps2 = POSH_ReadU32FromLittle( ibuffer );
668  img_file->GoTo( 128 );
669  //Set VSImage attributes
670  this->img_depth = header.pixelFormat.bpp;
671  this->sizeX = header.width;
672  this->sizeY = header.height;
673 
674  bool useDefaultType = false;
675  switch (this->img_depth)
676  {
677  case 24:
678  type = GL_RGB;
679  this->img_alpha = false;
680  break;
681  case 32:
682  type = GL_RGBA;
683  this->img_alpha = true;
684  break;
685  case 4:
686  type = GL_LUMINANCE;
687  break;
688  case 8:
689  type = GL_LUMINANCE_ALPHA;
690  this->img_alpha = true;
691  break;
692  case 0:
693  useDefaultType = true;
694  break;
695  default:
696  useDefaultType = true;
697  break;
698  }
699  switch (header.pixelFormat.fourcc[3])
700  {
701  case '1':
702  blockSize = 8;
703  if (type == GL_RGB || useDefaultType) {
704  this->img_depth = 24;
705  this->mode = _DXT1;
706  this->img_alpha = false;
707  type = GL_RGBA;
708  } else {
709  this->mode = _DXT1RGBA;
710  type = GL_RGBA;
711  this->img_alpha = true;
712  }
713  break;
714  case '3':
715  this->mode = _DXT3;
716  if (useDefaultType) {
717  this->img_alpha = true;
718  this->img_depth = 32;
719  type = GL_RGBA;
720  }
721  break;
722  case '5':
723  this->mode = _DXT5;
724  if (useDefaultType) {
725  this->img_alpha = true;
726  this->img_depth = 32;
727  type = GL_RGBA;
728  }
729  break;
730  default:
731  vs_dprintf(1, "VSImage ERROR : DDS Compression Scheme, impossible.[%c ;%c;%c;%c]!\n",header.pixelFormat.fourcc[0],header.pixelFormat.fourcc[1],
732  header.pixelFormat.fourcc[2],header.pixelFormat.fourcc[3]);
733  vs_dprintf( 1,"%s\n", img_file->GetFilename().c_str() );
734  throw (1);
735  }
736  inputSize = 0;
737  width = header.width;
738  height = header.height;
739  img_sides = SIDE_SINGLE;
740  img_nmips = header.nmips;
741  //Some DDS files may not have mipmaps
742  if (header.nmips == 0)
743  inputSize = ( (width+3)/4 )*( (height+3)/4 )*blockSize;
744  for (int i = 0; i < header.nmips; ++i) {
745  inputSize += ( (width+3)/4 )*( (height+3)/4 )*blockSize;
746  if (width != 1)
747  width >>= 1;
748  if (height != 1)
749  height >>= 1;
750  }
751  if ( header.dcaps2&(DDS_CUBEMAP|DDS_CUBEMAP_ALLFACES) ) {
752  vs_dprintf(3, "Reading Cubemap %s\n", img_file->GetFilename().c_str() );
753  inputSize = inputSize*6;
754  this->img_sides =
755  SIDE_POS_X|SIDE_NEG_X
756  |SIDE_POS_Y|SIDE_NEG_Y
757  |SIDE_POS_Z|SIDE_NEG_Z; //all sides, we don't support partial DDS files
758  this->img_color_type = 998; //Cubemap'd dds
759  } else {
760  this->img_color_type = 999; //Regular DDS
761  }
762  s = (unsigned char*) malloc( inputSize+3 );
763  sprintf( (char*) s, "%i", header.nmips ); //if cubemap, mips per face
764  img_file->Read( s+2, inputSize );
765  //At the end of execution what we have is the following:
766  //s contains the number of mipmaps then the main texture and all it's mipmaps
767  //sizeY is the height of the initial texture, sizeX is the width.
768  //mode is the compressed format of the texture. It is assumed to be rgba
769  //depth is the depth of the uncompressed image. not sure where this is used
770  //nmaps is the number of mipmaps
771  return s;
772  }
773  catch (...) {
774  if (s) free( s );
775  return NULL;
776  }
777 }
778 
779 void VSImage::AllocatePalette()
780 {
781  //FIXME deal with palettes and grayscale with alpha
782  if ( !(img_color_type&PNG_HAS_COLOR) || (img_color_type&PNG_HAS_PALETTE) ) {
783  if ( !(img_color_type&PNG_HAS_COLOR) ) {
784  palette = (unsigned char*) malloc( sizeof (unsigned char)*(256*4+1) );
785  for (unsigned int i = 0; i < 256; i++) {
786  palette[i*4] = i;
787  palette[i*4+1] = i;
788  palette[i*4+2] = i;
789  palette[i*4+3] = 255;
790  }
791  }
792  }
793 }
794 
795 VSError VSImage::WriteImage( char *filename,
796  unsigned char *data,
797  VSImageType type,
798  unsigned int width,
799  unsigned int height,
800  bool alpha,
801  char bpp,
802  VSFileType ft,
803  bool flip )
804 {
805  this->img_type = type;
806  VSFile f;
807  VSError err = f.OpenCreateWrite( filename, ft );
808  if (err > Ok) {
809  vs_dprintf(1,"VSImage ERROR : failed to open %s for writing \n",filename);
810  vs_dprintf( 1, img_file->GetFilename().c_str() );
812  }
813  VSError ret = this->WriteImage( &f, data, type, width, height, alpha, bpp, flip );
814  f.Close();
815  return ret;
816 }
817 
819  unsigned char *data,
820  VSImageType type,
821  unsigned int width,
822  unsigned int height,
823  bool alpha,
824  char bpp,
825  bool flip )
826 {
827  VSError ret = BadFormat;
828 
829  this->img_file = pf;
830  this->img_depth = bpp;
831  this->sizeX = width;
832  this->sizeY = height;
833  this->img_alpha = alpha;
834  this->flip = flip;
835  switch (type)
836  {
837  case PngImage:
838  ret = this->WritePNG( data );
839  break;
840  case JpegImage:
841  ret = this->WriteJPEG( data );
842  break;
843  case BmpImage:
844  ret = this->WriteBMP( data );
845  break;
846  default:
847  vs_dprintf(1, "VSImage ERROR : Unknown image format\n");
848  vs_dprintf( 1, "%s\n", img_file->GetFilename().c_str() );
850  }
851  this->img_file = NULL;
852  this->img_depth = 0;
853  this->sizeX = 0;
854  this->sizeY = 0;
855  this->img_alpha = false;
856  return ret;
857 }
858 
859 VSError VSImage::WritePNG( unsigned char *data )
860 {
861  png_structp png_ptr = png_create_write_struct
862  ( PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL );
863  if (!png_ptr)
864  return BadFormat;
865  png_infop info_ptr = png_create_info_struct( png_ptr );
866  if (!info_ptr) {
867  png_destroy_write_struct( &png_ptr, (png_infopp) NULL );
868  return BadFormat;
869  }
870  if ( setjmp( png_jmpbuf( png_ptr ) ) ) {
871  png_destroy_write_struct( &png_ptr, &info_ptr );
872  return BadFormat;
873  }
874  //if( !img_file->UseVolume())
875  //For now we always write to standard files
876  png_init_io( png_ptr, img_file->GetFP() );
877 
878  png_set_filter( png_ptr, 0, PNG_FILTER_NONE );
879  png_set_compression_level( png_ptr, Z_BEST_COMPRESSION );
880 
881  /* set other zlib parameters */
882  png_set_compression_mem_level( png_ptr, 8 );
883  png_set_compression_strategy( png_ptr, Z_DEFAULT_STRATEGY );
884  png_set_compression_window_bits( png_ptr, 15 );
885  png_set_compression_method( png_ptr, 8 );
886 
887  png_set_IHDR( png_ptr,
888  info_ptr,
889  this->sizeX,
890  this->sizeY,
891  this->img_depth,
892  this->img_alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
893  PNG_INTERLACE_NONE,
894  PNG_COMPRESSION_TYPE_DEFAULT,
895  PNG_FILTER_TYPE_DEFAULT );
896 
897  png_write_info( png_ptr, info_ptr );
898 # if __BYTE_ORDER != __BIG_ENDIAN
899  if (this->img_depth == 16)
900  png_set_swap( png_ptr );
901 #endif
902  int stride = (this->img_depth/8)*(this->img_alpha ? 4 : 3);
903  png_byte **row_pointers = new png_byte*[this->sizeY];
904  if (this->flip)
905  for (int i = this->sizeY-1, j = 0; i >= 0; i--, ++j)
906  row_pointers[j] = (png_byte*) &data[stride*i*sizeX];
907  else
908  for (unsigned int i = 0; i < this->sizeY; i++)
909  row_pointers[i] = (png_byte*) &data[stride*i*sizeX];
910  png_write_image( png_ptr, row_pointers );
911  png_write_end( png_ptr, info_ptr );
912  png_write_flush( png_ptr );
913  png_destroy_write_struct( &png_ptr, &info_ptr );
914 
915  free( data );
916  delete[] row_pointers;
917  return Ok;
918 }
919 
920 VSError VSImage::WriteJPEG( unsigned char *data )
921 {
922  return BadFormat;
923 }
924 
925 VSError VSImage::WriteBMP( unsigned char *data )
926 {
927  return BadFormat;
928 }
929