- Main Page
- Modules
- Data Structures
- Files

- Search for |

# image.c

    00001 /*
    00002
    00003   Velocity  v1.5
    00004   Copyright 2006, 2007 Gabriel Anderson
    00005
    00006   This program is free software; you can redistribute it and/or modify
    00007     it under the terms of the GNU General Public License as published by
    00008     the Free Software Foundation; either version 2 of the License, or
    00009     (at your option) any later version.
    00010
    00011     This program is distributed in the hope that it will be useful,
    00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00014     GNU General Public License for more details.
    00015
    00016     You should have received a copy of the GNU General Public License
    00017     along with this program; if not, write to the Free Software
    00018     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    00019
    00020 */
    00021
    00022 //---------------------------------------------------------------------------------//
    00023 // Includes                                                                        //
    00024 //---------------------------------------------------------------------------------//
    00025
    00026 #include "vlib.h"
    00027
    00028 //---------------------------------------------------------------------------------//
    00029 // Image                                                                           //
    00030 //---------------------------------------------------------------------------------//
    00031
    00032 static int getPow2 ( int value ) {
    00033   int b = value;
    00034   int n;
    00035
    00036   for ( n = 0; b != 0; n++ )
    00037     b >>= 1;
    00038
    00039   b = 1 << n;
    00040
    00041   if ( b == 2 * value )
    00042     b >>= 1;
    00043
    00044   return b;
    00045 }
    00046
    00047 static void load_png ( const char *filename, Image *img ) {
    00048   // open the image file
    00049   FILE *fp;
    00050
    00051   if ( ( fp = fopen ( filename, "rb" ) ) == NULL )
    00052     return;
    00053
    00054   png_structp png_ptr;
    00055   png_infop info_ptr;
    00056   unsigned int sig_read = 0;
    00057   png_uint_32 width, height;
    00058   int bit_depth, color_type, interlace_type, x, y;
    00059
    00060   png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
    00061   info_ptr = png_create_info_struct ( png_ptr );
    00062   png_init_io ( png_ptr, fp );
    00063   png_set_sig_bytes ( png_ptr, sig_read );
    00064   png_read_info ( png_ptr, info_ptr );
    00065   png_get_IHDR ( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL );
    00066
    00067   img->initWidth = width;
    00068   img->initHeight = height;
    00069   img->width = width;
    00070   img->height = height;
    00071   img->realWidth = getPow2 ( width );
    00072   img->realHeight = getPow2 ( height );
    00073
    00074   img->totalSize = img->realWidth * img->realHeight * sizeof ( u32 );
    00075
    00076   png_set_strip_16 ( png_ptr );
    00077   png_set_packing ( png_ptr );
    00078
    00079   if ( color_type == PNG_COLOR_TYPE_PALETTE )
    00080     png_set_palette_to_rgb ( png_ptr );
    00081
    00082   if ( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
    00083     png_set_gray_1_2_4_to_8 ( png_ptr );
    00084
    00085   if ( png_get_valid ( png_ptr, info_ptr, PNG_INFO_tRNS ) )
    00086     png_set_tRNS_to_alpha ( png_ptr );
    00087
    00088   png_set_filler ( png_ptr, 0xff, PNG_FILLER_AFTER );
    00089
    00090   img->data = ( u32* ) malloc ( img->totalSize );
    00091
    00092   u32* line = ( u32* ) malloc ( width * 4 );
    00093
    00094   for ( y = 0; y < ( int ) height; y++ ) {
    00095     png_read_row ( png_ptr, ( u8* ) line, png_bytep_NULL );
    00096     for ( x = 0; x < ( int ) width; x++ ) {
    00097       u32 color = line[x];
    00098       img->data[x + y * ( int ) img->realWidth] =  color;
    00099     }
    00100   }
    00101
    00102   free ( line );
    00103
    00104   png_read_end ( png_ptr, info_ptr );
    00105   png_destroy_read_struct ( &png_ptr, &info_ptr, png_infopp_NULL );
    00106
    00107   // close the file
    00108   fclose ( fp );
    00109 }
    00110
    00111 // xart's png loader. It's not working atm (probably due to variable type issues), but once I get it working
    00112 //I'll do a head to head comparison between this and my current png loader to see which one can load the quickest.
    00113 /*static void loadPNG(const char *filename, Image *img)
    00114 {
    00115   Image *img = (Image*) malloc(sizeof(Image));
    00116   img->location = location;
    00117
    00118   int number_passes, pass;
    00119   png_structp png_ptr;
    00120   png_infop info_ptr;
    00121   unsigned int sig_read = 0;
    00122   png_uint_32 width, height;
    00123   int bit_depth, color_type, interlace_type, x, y;
    00124   u32* line;
    00125   FILE *fp;
    00126
    00127   if((fp = fopen(filename, "rb")) == NULL)
    00128     return NULL;
    00129
    00130   fseek(fp,0,SEEK_SET);
    00131
    00132   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    00133   if (png_ptr == NULL)
    00134   {
    00135     fclose(fp);
    00136     return NULL;
    00137   }
    00138
    00139   // Optinal error function currently not used in this class
    00140   //png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, user_warning_fn);
    00141   info_ptr = png_create_info_struct(png_ptr);
    00142   if (info_ptr == NULL)
    00143   {
    00144     fclose(fp);
    00145     png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
    00146     return NULL;
    00147   }
    00148
    00149   png_init_io(png_ptr, fp);
    00150   png_set_sig_bytes(png_ptr, sig_read);
    00151   png_read_info(png_ptr, info_ptr);
    00152   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL);
    00153
    00154   if (width > 512 || height > 512)
    00155   {
    00156     fclose(fp);
    00157     png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
    00158     return NULL;
    00159   }
    00160
    00161   img->width = width;
    00162   img->height = height;
    00163   img->initWidth = width;
    00164   img->initHeight = height;
    00165   img->realWidth = getPow2(width);
    00166   img->realHeight = getPow2(height);
    00167
    00168   // New (the check) - Convert 16-bits per colour component to 8-bits per colour component.
    00169   if (bit_depth == 16) png_set_strip_16(png_ptr);
    00170
    00171   // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
    00172   // byte into separate bytes (useful for paletted and grayscale images).
    00173   png_set_packing(png_ptr);
    00174
    00175   if (color_type == PNG_COLOR_TYPE_PALETTE)
    00176     png_set_palette_to_rgb(png_ptr);
    00177
    00178   // New - Convert grayscale to RGB triplets
    00179   if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
    00180     png_set_gray_to_rgb(png_ptr);
    00181
    00182   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    00183     png_set_gray_1_2_4_to_8(png_ptr);
    00184
    00185   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    00186     png_set_tRNS_to_alpha(png_ptr);
    00187
    00188   png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
    00189
    00190   u32 *data = (u32 *) memalign(16, img->width * img->height * sizeof(u32));
    00191
    00192   if (!data)
    00193   {
    00194     fclose(fp);
    00195     png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
    00196     return NULL;
    00197   }
    00198
    00199   line = (u32*) malloc(width * 4);
    00200   if (!line)
    00201   {
    00202     free(data);
    00203     fclose(fp);
    00204     png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
    00205     return NULL;
    00206   }
    00207
    00208   // New - Turn on interlace handling.
    00209   number_passes = png_set_interlace_handling(png_ptr);
    00210
    00211   // New - Call to gamma correct and add the background to the palette
    00212   // and update info structure.
    00213   png_read_update_info(png_ptr, info_ptr);
    00214
    00215   // New - Read the image, one line at a line (easier to debug!)
    00216   for (pass = 0; pass < number_passes; pass++) {
    00217       for (y = 0; y < (int)height; y++)
    00218       {
    00219          png_read_row(png_ptr, (u8*) line, png_bytep_NULL);
    00220
    00221          for (x = 0; x < (int)width; x++)
    00222          {
    00223             u32 color = line[x];
    00224             data[x + y * (int)img->width] = color;
    00225          }
    00226       }
    00227   }
    00228   free(line);
    00229
    00230   png_read_end(png_ptr, info_ptr);
    00231   png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
    00232   fclose(fp);
    00233   img->data=(u32*)data;
    00234
    00235   return img;
    00236 } */
    00237
    00238 // Works, but needs to check file headers to see whether or not it should
    00239 //flip/invert the image's pixels.
    00240 static void load_tga ( const char *filename, Image *img ) {
    00241   // open the image file
    00242   FILE *fp;
    00243
    00244   if ( ( fp = fopen ( filename, "rb" ) ) == NULL )
    00245     return;
    00246
    00247   unsigned char ucharBad; // garbage data
    00248
    00249   short int sintBad;    // garbage data
    00250
    00251   int colorMode;      // 4 for RGBA, 3 for RGB
    00252
    00253   long imageIdx;      // counter variable
    00254
    00255   unsigned char colorSwap;  // swap variable
    00256
    00257   unsigned char imageTypeCode;
    00258
    00259   unsigned char bitCount;
    00260
    00261   // read first two bytes of garbage
    00262   fread ( &ucharBad, sizeof ( unsigned char ), 1, fp );
    00263
    00264   fread ( &ucharBad, sizeof ( unsigned char ), 1, fp );
    00265
    00266   // read in the image type
    00267   fread ( &imageTypeCode, sizeof ( unsigned char ), 1, fp );
    00268
    00269   // for our purposes, the image type should be either a 2 or a 3
    00270   if ( ( imageTypeCode != 2 ) && ( imageTypeCode != 3 ) ) {
    00271     fclose ( fp );
    00272     return;
    00273   }
    00274
    00275   // read 13 bytes of garbage data
    00276   fread ( &sintBad, sizeof ( short int ), 1, fp );
    00277
    00278   fread ( &sintBad, sizeof ( short int ), 1, fp );
    00279
    00280   fread ( &ucharBad, sizeof ( unsigned char ), 1, fp );
    00281
    00282   fread ( &sintBad, sizeof ( short int ), 1, fp );
    00283
    00284   fread ( &sintBad, sizeof ( short int ), 1, fp );
    00285
    00286   // read image dimensions
    00287   fread ( &img->initWidth, sizeof ( short int ), 1, fp );
    00288
    00289   fread ( &img->initHeight, sizeof ( short int ), 1, fp );
    00290
    00291   img->width = img->initWidth;
    00292
    00293   img->height = img->initHeight;
    00294
    00295   img->realWidth = getPow2 ( img->initWidth );
    00296
    00297   img->realHeight = getPow2 ( img->initHeight );
    00298
    00299   // read bit depth
    00300   fread ( &bitCount, sizeof ( unsigned char ), 1, fp );
    00301
    00302   // read garbage
    00303   fread ( &ucharBad, sizeof ( unsigned char ), 1, fp );
    00304
    00305   // colormode -> 3 = BGR, 4 = BGRA
    00306   colorMode = bitCount / 8;
    00307
    00308   img->totalSize = img->realWidth * img->realHeight * colorMode;
    00309
    00310   // allocate memory for image data
    00311   img->data = ( u32* ) malloc ( sizeof ( u32 ) * img->totalSize );
    00312
    00313   // read image data
    00314   fread ( img->data, sizeof ( u32 ), img->totalSize, fp );
    00315
    00316   // change BGR to RGB
    00317   for ( imageIdx = 0; imageIdx < img->totalSize; imageIdx += colorMode ) {
    00318     colorSwap = img->data[imageIdx];
    00319     img->data[imageIdx] = img->data[imageIdx+2];
    00320     img->data[imageIdx + 2] = colorSwap;
    00321   }
    00322
    00323   // close the file
    00324   fclose ( fp );
    00325 }
    00326
    00327 // Bronx's jpeg loader. Broken atm mainly due to variable type conflicts/issues.
    00328 //Compiles fine though :S
    00329 static void load_jpg ( const char *filename, Image *img ) {
    00330
    00331   struct jpeg_decompress_struct cinfo;
    00332
    00333   // open the image file
    00334   FILE *fp;
    00335
    00336   if ( ( fp = fopen ( filename, "rb" ) ) == NULL )
    00337     return;
    00338
    00339   pspDebugScreenPrintf ( "Blah" );
    00340
    00341   sceKernelDelayThread ( 10000 );
    00342
    00343   // Create an error manager
    00344
    00345   struct jpeg_error_mgr jerr;
    00346
    00347   // Make compression info object point to the error handler address
    00348   cinfo.err = jpeg_std_error ( &jerr );
    00349
    00350   // Init the decompression object
    00351   jpeg_create_decompress ( &cinfo );
    00352
    00353   // Specify the data source (the image)
    00354   jpeg_stdio_src ( &cinfo, fp );
    00355
    00356   // Read in the header of the JPEG file
    00357   jpeg_read_header ( &cinfo, TRUE );
    00358
    00359   // Decompress the JPEG file with out compression info
    00360   jpeg_start_decompress ( &cinfo );
    00361
    00362   // Get image dimensions and row span to read in pixel data
    00363   int rowSpan = cinfo.image_width * cinfo.num_components;
    00364
    00365   img->initWidth = cinfo.image_width;
    00366
    00367   img->initHeight = cinfo.image_height;
    00368
    00369   img->realWidth = getPow2 ( cinfo.image_width );
    00370
    00371   img->realHeight = getPow2 ( cinfo.image_height );
    00372
    00373   img->totalSize = img->initWidth * img->initHeight * sizeof ( u32 );
    00374
    00375   // Allocate memory for the pixel buffer
    00376   img->data = ( u32* ) malloc ( img->totalSize );
    00377
    00378   // Create an array of row pointers
    00379   u32* rowPtr = ( u32* ) malloc ( img->realHeight * sizeof ( u32 ) );
    00380
    00381   int i;
    00382
    00383   for ( i = 0; i < img->realHeight; i++ )
    00384     rowPtr[i] = ( unsigned char ) img->data[i * rowSpan];
    00385
    00386   // Extract all the pixel data
    00387   int rowsRead = 0;
    00388
    00389   while ( cinfo.output_scanline < cinfo.output_height )
    00390     // Read in the current row of pixels and increase the rowsRead count
    00391     rowsRead += jpeg_read_scanlines ( &cinfo, ( JSAMPARRAY ) & rowPtr[rowsRead], cinfo.output_height - rowsRead );
    00392
    00393   free ( rowPtr );
    00394
    00395   // Finish decompressing the data
    00396   jpeg_finish_decompress ( &cinfo );
    00397
    00398   // Release all memory for reading and decoding the jpeg
    00399   jpeg_destroy_decompress ( &cinfo );
    00400
    00401   fclose ( fp );
    00402 }
    00403
    00404 static void swizzle_image ( Image *img ) {
    00405   // Swizzle the texture
    00406   int rowblocks = ( ( img->realWidth * 4 ) / 16 );
    00407   int rowblocks_add = ( rowblocks - 1 ) * 128;
    00408   unsigned int block_address = 0;
    00409   unsigned int *src = ( unsigned int* ) img->data;
    00410
    00411   static u8 *t_data;
    00412   t_data = ( u8* ) malloc ( img->totalSize );
    00413
    00414   int j;
    00415   for ( j = 0; j < img->realHeight; j++, block_address += 16 ) {
    00416     unsigned int *block = ( unsigned int* ) ( ( unsigned int ) & t_data[block_address] | 0x40000000 );
    00417     int i;
    00418
    00419     for ( i = 0; i < rowblocks; i++ ) {
    00420       *block++ = *src++;
    00421       *block++ = *src++;
    00422       *block++ = *src++;
    00423       *block++ = *src++;
    00424       block += 28;
    00425     }
    00426
    00427     if ( ( j&0x7 ) == 0x7 )
    00428       block_address += rowblocks_add;
    00429   }
    00430
    00431   free ( img->data );
    00432
    00433   if ( img->location )
    00434     img->data = ( u32* ) valloc ( img->totalSize );
    00435   else
    00436     img->data = ( u32* ) malloc ( img->totalSize );
    00437
    00438   //img->data = (u32*)t_data;
    00439   memcpy ( img->data, t_data, img->totalSize );
    00440
    00441   free ( t_data );
    00442
    00443   sceKernelDcacheWritebackAll();
    00444 }
    00445
    00446 Image *load_image ( const char *filename, int location ) {
    00447   // Allocate some memory for our image
    00448   Image *img = ( Image* ) malloc ( sizeof ( Image ) );
    00449   img->location = location;
    00450
    00451   // Determine the filetype
    00452
    00453   const char *suffix = strrchr ( filename, '.' );
    00454
    00455   // Load image by it's filetype
    00456   if ( strcmp ( suffix, ".png" ) == 0 )
    00457     load_png ( filename, img );
    00458
    00459   //else if(strcmp(suffix,".bmp") == 0)
    00460   // bitmap file loader goes here
    00461   else if ( strcmp ( suffix, ".tga" ) == 0 )
    00462     load_tga ( filename, img );
    00463   else if ( strcmp ( suffix, ".jpg" ) == 0 )
    00464     load_jpg ( filename, img );
    00465
    00466   sceKernelDcacheWritebackAll();
    00467
    00468   // Swizzle the texture
    00469   swizzle_image ( img );
    00470
    00471   img->x = 0.0f;
    00472   img->y = 0.0f;
    00473   img->startX = 0.0f;
    00474   img->startY = 0.0f;
    00475   img->endX = img->width;
    00476   img->endY = img->height;
    00477   img->angle = 0.0f;
    00478   img->centerX = 0.0f;
    00479   img->centerY = 0.0f;
    00480
    00481   // Clear bad data from the cache
    00482   sceKernelDcacheWritebackAll();
    00483
    00484   return img;
    00485 }
    00486
    00487 void unload_image ( Image *img ) {
    00488   if ( img->location )
    00489     vfree ( img->data );
    00490   else
    00491     free ( img->data );
    00492
    00493   free ( img );
    00494 }
    00495
    00496 void draw_image ( Image *img ) {
    00497   if ( !img->width || !img->endX )
    00498     return;
    00499
    00500   float u_end = img->endX - img->startX;
    00501   float u_width = img->endX / ( img->width / 64.0f );
    00502   float cur_u = img->startX;
    00503   float cur_x = 0.0f;
    00504
    00505   // Some matrix stuff to position the matrix and rotate it. Extremely fast though, since it uses vfpu to get the job done
    00506   vfpu_identity_m ( &m_ortho_view );
    00507   vfpu_translate_m ( &m_ortho_view, img->x, img->y, 0.0f );
    00508
    00509   vfpu_identity_m ( &m_ortho_model );
    00510   vfpu_rotateZ_m ( &m_ortho_model, img->angle );
    00511   vfpu_translate_m ( &m_ortho_model, img->centerX, img->centerY, 0.0f );
    00512
    00513   sceGuSetMatrix ( GU_PROJECTION, &m_ortho );
    00514   sceGuSetMatrix ( GU_VIEW, &m_ortho_view );
    00515   sceGuSetMatrix ( GU_MODEL, &m_ortho_model );
    00516
    00517   float u = 1.0f / ( ( float ) img->initWidth );
    00518   float v = 1.0f / ( ( float ) img->initHeight );
    00519   sceGuTexScale ( u, v );
    00520
    00521   // Set texture
    00522   sceGuTexImage ( 0, img->realWidth, img->realHeight, img->realWidth, ( void* ) img->data );
    00523
    00524   while ( cur_x != img->width ) {
    00525     TP_Vertex_3D* vertices = ( TP_Vertex_3D* ) sceGuGetMemory ( 4 * sizeof ( TP_Vertex_3D ) );
    00526
    00527     vertices[0].u = cur_u;
    00528     vertices[0].v = img->startY;
    00529     vertices[0].x = cur_x;
    00530     vertices[0].y = 0.0f;
    00531     vertices[0].z = 0.0f;
    00532
    00533     vertices[2].u = cur_u;
    00534     vertices[2].v = img->endY;
    00535     vertices[2].x = cur_x;
    00536     vertices[2].y = img->height;
    00537     vertices[2].z = 0.0f;
    00538
    00539     cur_u += u_width;
    00540     cur_x += 64.0f;
    00541
    00542     if ( cur_x > img->width ) {
    00543       cur_x = img->width;
    00544       cur_u = u_end;
    00545     }
    00546
    00547     vertices[1].u = cur_u;
    00548     vertices[1].v = img->startY;
    00549     vertices[1].x = cur_x;
    00550     vertices[1].y = 0.0f;
    00551     vertices[1].z = 0.0f;
    00552
    00553     vertices[3].u = cur_u;
    00554     vertices[3].v = img->endY;
    00555     vertices[3].x = cur_x;
    00556     vertices[3].y = img->height;
    00557     vertices[3].z = 0.0f;
    00558
    00559     sceGuDrawArray ( GU_TRIANGLE_STRIP, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 4, 0, vertices );
    00560   }
    00561   sceGuTexScale ( 1.0f, 1.0f );
    00562 }
    00563
    00564 void set_linear_filter ( short state ) {
    00565   if ( drawingStarted ) {
    00566     sceGuTexFilter ( state, state );
    00567     return;
    00568   }
    00569
    00570   sceGuStart ( GU_DIRECT, DList );
    00571   sceGuTexFilter ( state, state );
    00572   sceGuFinish();
    00573   sceGuSync ( 0, 0 );
    00574 }