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 }

Generated on Tue Mar 20 23:01:06 2007 for vLib by  doxygen 1.4.7