Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.         SDL_anim:  an animation library for SDL
  3.         Copyright (C) 2001, 2002  Michael Leonhard
  4.  
  5.         This library is free software; you can redistribute it and/or
  6.         modify it under the terms of the GNU Library General Public
  7.         License as published by the Free Software Foundation; either
  8.         version 2 of the License, or (at your option) any later version.
  9.  
  10.         This library 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 GNU
  13.         Library General Public License for more details.
  14.  
  15.         You should have received a copy of the GNU Library General Public
  16.         License along with this library; if not, write to the Free
  17.         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.        
  19.         Michael Leonhard
  20.         mike@tamale.net
  21. */
  22.  
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <png.h>
  27. #include "SDL_anim.h"
  28.  
  29. /* deal with MSVC++ crappiness */
  30. #ifdef WIN32UNDEFINED
  31.         #define strcasecmp _strcmpi
  32.         #endif
  33.  
  34. void Anim_Free( SDL_Animation *anim ) {
  35.         SDL_FreeSurface( anim->surface );
  36.         free( anim );
  37.         }
  38.  
  39. int Anim_GetFrameNum( SDL_Animation *anim, Uint32 start, Uint32 now ) {
  40.         int mspf, ms, frame;
  41.         if( now < start ) return 0;
  42.  
  43.         mspf = anim->duration / anim->frames;
  44.         ms = now - start;
  45.         if( mspf == 0 ) frame = 0;
  46.         else frame = ms / mspf;
  47.  
  48.         return frame;
  49.         }
  50.  
  51. void Anim_GetFrameRect( SDL_Animation *anim, int frame, SDL_Rect *rect ) {
  52.         rect->x = anim->w * (frame % anim->frames);
  53.         rect->y = 0;
  54.         rect->w = anim->w;
  55.         rect->h = anim->h;
  56.         }
  57.  
  58. int Anim_BlitFrame( SDL_Animation *anim, Uint32 start, Uint32 now, SDL_Surface *dest, SDL_Rect *dr ) {
  59.         int frame;
  60.         frame = Anim_GetFrameNum( anim, start, now );
  61.         return Anim_BlitFrameNum( anim, frame, dest, dr );
  62.         }
  63.  
  64. int Anim_BlitFrameNum( SDL_Animation *anim, int frame, SDL_Surface *dest, SDL_Rect *dr ) {
  65.         SDL_Rect rect;
  66.         Anim_GetFrameRect( anim, frame, &rect );
  67.         return SDL_BlitSurface( anim->surface, &rect, dest, dr );
  68.         }
  69.  
  70. int Anim_DisplayFormat( SDL_Animation *anim ) {
  71.         struct SDL_Surface *newsurface;
  72.         if( SDL_WasInit( SDL_INIT_VIDEO ) == 0 ) return 0;/*"Video is not initialized.\n"*/
  73.         newsurface = SDL_DisplayFormatAlpha( anim->surface );
  74.         if( !newsurface ) return 0;
  75.         anim->surface = newsurface;
  76.         return 1;      
  77.         }
  78.  
  79. int DoAnimFormat( char *text, int *duration, int *framewidth, int *numframes ) {
  80.         char *tok;
  81.         SDL_printf( "file is \"%s\"\n", text );
  82.        
  83.         /* SDL_anim */
  84.         tok = strtok( text, " " );
  85.         if( !tok ) return 0;
  86.         if( strcasecmp( tok, "SDL_anim" ) != 0 ) {
  87.                 SDL_printf( "no SDL_anim\n" );
  88.                 return 0;
  89.                 }
  90.        
  91.         /* duration */
  92.         tok = strtok( NULL, " " );
  93.         if( !tok ) return 0;
  94.         *duration = atoi( tok );
  95.         if( *duration < 1 ) {
  96.                 SDL_printf( "no duration\n" );
  97.                 return 0;
  98.                 }
  99.  
  100.         /* framewidth */
  101.         tok = strtok( NULL, " " );
  102.         if( !tok ) return 0;
  103.         *framewidth = atoi( tok );
  104.         if( *framewidth < 1 ) {
  105.                 SDL_printf( "no framewidth\n" );
  106.                 return 0;
  107.                 }
  108.  
  109.         /* numframes */
  110.         tok = strtok( NULL, " " );
  111.         if( !tok ) return 0;
  112.         *numframes = atoi( tok );
  113.         if( *numframes < 1 ) {
  114.                 SDL_printf( "no numframes\n" );
  115.                 return 0;
  116.                 }
  117.  
  118.         return 1;
  119.         }
  120.  
  121. struct SDL_Animation *Anim_Load( const char *file ) {
  122.         int ckey = -1, i;
  123.         char buf[8];
  124.         static FILE *fp;  /* "static" prevents setjmp corruption */
  125.         png_structp read_ptr;
  126.         png_infop read_info_ptr, end_info_ptr;
  127.         png_bytep *row_pointers;
  128.         png_textp text_ptr;
  129.         int num_text, t;
  130.         int interlace_type, compression_type, filter_type, bit_depth, color_type;
  131.         png_uint_32 width, height, row;
  132.         int duration, framewidth, numframes;
  133.  
  134.         png_color_16p background;
  135.         double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
  136.         double gamma;
  137.         int intent;
  138.         png_uint_16p hist;
  139.         png_uint_32 offset_x, offset_y;
  140.         int unit_type;
  141.         png_charp purpose, units;
  142.         png_charpp params;
  143.         png_int_32 X0, X1;
  144.         int type, nparams;
  145.         png_uint_32 res_x, res_y;
  146. /*      png_colorp palette;
  147.         int num_palette;
  148. */      png_color_8p sig_bit;
  149.         png_bytep trans;
  150.         int num_trans;
  151.         png_color_16p trans_values;
  152.  
  153.         Uint32 Rmask;
  154.         Uint32 Gmask;
  155.         Uint32 Bmask;
  156.         Uint32 Amask;
  157.  
  158.         SDL_Animation *anim;
  159.         SDL_Surface *surface;
  160.         SDL_Palette *palette;
  161.  
  162.         if( !file ) return NULL;
  163.  
  164. /*      printf( "opening file \"%s\"\n", file );
  165. */
  166.         /* open the file handle */
  167.         fp = fopen( file, "rb" );
  168.         if( fp == NULL ) {
  169.                 SDL_printf( "fopen() failed\n" );
  170.                 return NULL;
  171.                 }
  172.  
  173.         /* check if it's PNG */
  174.         if( fread( buf, 1, 8, fp ) != 8 ) {
  175.                 SDL_printf( "fread() failed\n" );
  176.                 return NULL;
  177.                 }
  178.         if( png_sig_cmp( buf, (png_size_t)0, 8 ) ) {
  179.                 SDL_printf( "not a PNG file\n" );
  180.                 return NULL;
  181.                 }
  182.         fseek( fp, 0, SEEK_SET );
  183.  
  184.         /* allocate read structure */
  185.         read_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL );
  186.         if( read_ptr == NULL ) {
  187.                 SDL_printf( "png_create_read_struct() failed\n" );
  188.                 return NULL;
  189.                 }
  190.        
  191.         /* allocate read info structure */
  192.         read_info_ptr = png_create_info_struct( read_ptr );
  193.         if( read_info_ptr == NULL ) {
  194.                 SDL_printf( "png_create_info_struct() failed\n" );
  195.                 return NULL;
  196.                 }
  197.         end_info_ptr = png_create_info_struct( read_ptr );
  198.         if( end_info_ptr == NULL ) {
  199.                 SDL_printf( "png_create_info_struct() failed\n" );
  200.                 return NULL;
  201.                 }
  202.  
  203.         /* set error handler code */
  204.         if( setjmp( read_ptr->jmpbuf ) ) {
  205.                 SDL_printf( "libpng read error\n" );
  206.                 return NULL;
  207.                 }
  208.  
  209.         /* initialize stream */
  210.         png_init_io( read_ptr, fp );
  211.         png_set_read_status_fn( read_ptr, NULL );
  212.  
  213.         /* read png info struct */
  214.         png_read_info( read_ptr, read_info_ptr );
  215.  
  216.         /* get the info */
  217.         if( !png_get_IHDR( read_ptr, read_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type ) ) {
  218.                 SDL_printf( "png_get_IHDR() failed\n" );
  219.                 return NULL;
  220.                 }
  221.  
  222.         /* background color */
  223.         png_get_bKGD( read_ptr, read_info_ptr, &background );
  224.  
  225.         png_get_cHRM( read_ptr, read_info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y );
  226.  
  227.         /* gamma */
  228.         png_get_gAMA( read_ptr, read_info_ptr, &gamma );
  229.  
  230.         /* rendering intent */
  231.         png_get_sRGB( read_ptr, read_info_ptr, &intent );
  232.  
  233.         /* Histogram */
  234.         png_get_hIST( read_ptr, read_info_ptr, &hist );
  235.  
  236.         /* offsets */
  237.         png_get_oFFs( read_ptr, read_info_ptr, &offset_x, &offset_y, &unit_type );
  238.        
  239.         png_get_pCAL( read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, &params );
  240.  
  241.         /* pixel density */
  242.         png_get_pHYs( read_ptr, read_info_ptr, &res_x, &res_y, &unit_type );
  243.  
  244. /*      png_get_PLTE( read_ptr, read_info_ptr, &palette, &num_palette );
  245. */
  246.         /* significant bits */
  247.         png_get_sBIT( read_ptr, read_info_ptr, &sig_bit );
  248.  
  249.         /* transparency */
  250.         if( png_get_tRNS( read_ptr, read_info_ptr, &trans, &num_trans, &trans_values ) ) {
  251.                 if( color_type == PNG_COLOR_TYPE_PALETTE ) {
  252.                         if( num_trans == 1 ) ckey = trans[0];
  253.                         else png_set_expand( read_ptr );
  254.                         }
  255.                 else ckey = 0; /* actual value will be set later */
  256.                 }
  257.  
  258.         /* text chunks */
  259.         num_text = 0;
  260.         if( !png_get_text( read_ptr, read_info_ptr, &text_ptr, &num_text ) ) {
  261.                 SDL_printf( "file has no text chunks\n" );
  262.                 return NULL;
  263.                 }
  264.         for( t = 0; t < num_text; t++ ) {
  265.                 if( strcasecmp( text_ptr[t].key, "format" ) == 0 ) {
  266.                         if( DoAnimFormat( text_ptr[t].text, &duration, &framewidth, &numframes ) ) break;
  267.                         }
  268.                 }
  269.         if( t == num_text ) {
  270.                 SDL_printf( "file is not an SDL_anim PNG\n" );
  271.                 return NULL;
  272.                 }
  273.  
  274.         png_set_strip_16( read_ptr );
  275.         png_set_packing( read_ptr );
  276.         if(color_type == PNG_COLOR_TYPE_GRAY)
  277.                 png_set_expand( read_ptr );
  278.  
  279.         /* Allocate the SDL surface to hold the image */
  280.         Rmask = Gmask = Bmask = Amask = 0;
  281.         if( color_type != PNG_COLOR_TYPE_PALETTE ) {
  282.                 if( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
  283.                         Rmask = 0x000000FF;
  284.                         Gmask = 0x0000FF00;
  285.                         Bmask = 0x00FF0000;
  286.                         Amask = (read_info_ptr->channels == 4)? 0xFF000000 : 0;
  287.                         }
  288.                 else {
  289.                         int s = (read_info_ptr->channels == 4) ? 0 : 8;
  290.                         Rmask = 0xFF000000 >> s;
  291.                         Gmask = 0x00FF0000 >> s;
  292.                         Bmask = 0x0000FF00 >> s;
  293.                         Amask = 0x000000FF >> s;
  294.                         }
  295.                 }
  296.  
  297.         surface = SDL_AllocSurface( SDL_SWSURFACE, width, height, bit_depth * read_info_ptr->channels, Rmask, Gmask, Bmask, Amask );
  298.         if( surface == NULL ) {
  299.                 Anim_SetError("Out of memory");
  300.                 return NULL;
  301.                 }
  302.  
  303.         if(ckey != -1) {
  304.                 if( color_type != PNG_COLOR_TYPE_PALETTE ) ckey = SDL_MapRGB( surface->format, (Uint8)trans_values->red, (Uint8)trans_values->green, (Uint8)trans_values->blue );
  305.                 SDL_SetColorKey( surface, SDL_SRCCOLORKEY, ckey );
  306.                 }
  307.  
  308.         /* allocate row pointers */
  309.         row_pointers = (png_bytep *)malloc( sizeof( png_bytep ) * height );
  310.         if( row_pointers == NULL ) {
  311.                 SDL_printf( "malloc() failed\n" );
  312.                 return NULL;
  313.                 }
  314.         for( row = 0; row < height; row++ ) {
  315.                 row_pointers[row] = (Uint8 *)surface->pixels + row * surface->pitch;
  316.                 }
  317.  
  318.         png_read_image( read_ptr, row_pointers );
  319.  
  320.         /* end io */
  321. /*      printf( "done\n" );
  322. */      png_read_end( read_ptr, end_info_ptr );
  323.  
  324.         /* cleanup */
  325.         png_destroy_read_struct( &read_ptr, &read_info_ptr, &end_info_ptr);
  326.         fclose( fp );
  327.  
  328.         /* Load the palette, if any */
  329.         palette = surface->format->palette;
  330.         if( palette ) {
  331.                 if(color_type == PNG_COLOR_TYPE_GRAY) {
  332.                         palette->ncolors = 256;
  333.                         for( i = 0; i < 256; i++ ) {
  334.                                 palette->colors[i].r = i;
  335.                                 palette->colors[i].g = i;
  336.                                 palette->colors[i].b = i;
  337.                                 }
  338.                         }
  339.                 else if( read_info_ptr->num_palette > 0 ) {
  340.                         palette->ncolors = read_info_ptr->num_palette;
  341.                         for( i = 0; i < read_info_ptr->num_palette; ++i ) {
  342.                                 palette->colors[i].b = read_info_ptr->palette[i].blue;
  343.                                 palette->colors[i].g = read_info_ptr->palette[i].green;
  344.                                 palette->colors[i].r = read_info_ptr->palette[i].red;
  345.                                 }
  346.                         }
  347.                 }
  348.        
  349.         anim = (struct SDL_Animation *)malloc( sizeof( struct SDL_Animation ) );
  350.         if( !anim ) {
  351.                 SDL_printf( "malloc() failed\n" );
  352.                 return NULL;
  353.                 }
  354.  
  355.         anim->surface = surface;
  356.         anim->w = framewidth;
  357.         anim->h = height;
  358.         anim->frames = numframes;
  359.         anim->duration = duration;
  360.  
  361.         return anim;
  362.         }
  363.