diff options
Diffstat (limited to 'modules/mod_map/file_png.c')
-rw-r--r-- | modules/mod_map/file_png.c | 629 |
1 files changed, 629 insertions, 0 deletions
diff --git a/modules/mod_map/file_png.c b/modules/mod_map/file_png.c new file mode 100644 index 0000000..711e63d --- /dev/null +++ b/modules/mod_map/file_png.c @@ -0,0 +1,629 @@ +/* + * Copyright © 2006-2016 SplinterGU (Fenix/Bennugd) + * Copyright © 2002-2006 Fenix Team (Fenix) + * Copyright © 1999-2002 José Luis Cebrián Pagüe (Fenix) + * + * This file is part of Bennu - Game Development + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + */ + +/* --------------------------------------------------------------------------- */ + +#include <png.h> + +#include "mod_map.h" + +/* --------------------------------------------------------------------------- */ + +static void user_read_data( png_structp png_ptr, png_bytep data, png_size_t length ) +{ + file * png = (file *)png_get_io_ptr( png_ptr ); + file_read( png, data, length ) ; +} + +GRAPH * gr_read_png( const char * filename ) +{ + GRAPH * bitmap ; + unsigned int n, x ; + uint16_t * ptr ; + uint32_t * ptr32 ; + uint32_t * orig ; + uint32_t * row ; + uint32_t Rshift, Gshift, Bshift ; + uint32_t Rmask, Gmask, Bmask ; + + png_bytep * rowpointers ; + + png_structp png_ptr ; + png_infop info_ptr, end_info ; + png_uint_32 width, height, rowbytes; + int depth, color ; + + /* Abre el fichero y se asegura de que screen está inicializada */ + + file * png = file_open( filename, "rb" ) ; + if ( !png ) return NULL; + + /* Prepara las estructuras internas */ + + png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ) ; + if ( !png_ptr ) + { + file_close( png ); + return NULL; + } + + info_ptr = png_create_info_struct( png_ptr ) ; + end_info = png_create_info_struct( png_ptr ) ; + if ( !info_ptr || !end_info ) + { + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ) ; + file_close( png ) ; + return NULL; + } + + /* Rutina de error */ + +#if (PNG_LIBPNG_VER>=10500) + if ( setjmp( png_jmpbuf( png_ptr ) ) ) +#else + if ( setjmp( png_ptr->jmpbuf ) ) +#endif + { + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ) ; + file_close( png ) ; + return NULL; + } + + /* Recupera información sobre el PNG */ + + png_set_read_fn( png_ptr, png, user_read_data ) ; + png_read_info( png_ptr, info_ptr ) ; + png_get_IHDR( png_ptr, info_ptr, &width, &height, &depth, &color, 0, 0, 0 ) ; + + row = malloc( sizeof( uint32_t ) * width ); + if ( !row ) + { + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ) ; + file_close( png ) ; + return NULL; + } + + rowpointers = malloc( sizeof( png_bytep ) * height ); + if ( !rowpointers ) + { + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ) ; + free( row ) ; + file_close( png ) ; + return NULL; + } + + /* Configura los distintos modos disponibles */ +/* + if ( ( color == PNG_COLOR_TYPE_GRAY && depth == 1 ) || color == PNG_COLOR_TYPE_GRAY_ALPHA ) + { + png_set_gray_to_rgb( png_ptr ); + if ( color == PNG_COLOR_TYPE_GRAY ) png_set_filler( png_ptr, 0xFF, PNG_FILLER_AFTER ) ; + } +*/ + if ( depth == 16 ) png_set_strip_16( png_ptr ) ; + + if ( color == PNG_COLOR_TYPE_RGB ) png_set_filler( png_ptr, 0xFF, PNG_FILLER_AFTER ) ; + + png_set_bgr( png_ptr ) ; + + /* Recupera el fichero, convirtiendo a 16 bits si es preciso */ + + rowbytes = png_get_rowbytes( png_ptr, info_ptr ) ; + bitmap = bitmap_new( 0, width, height, ( color == PNG_COLOR_TYPE_GRAY ) ? depth : ( color == PNG_COLOR_TYPE_PALETTE ) ? 8 : ( sys_pixel_format->depth == 16 ? 16 : 32 ) ) ; + if ( !bitmap ) + { + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ) ; + free( rowpointers ) ; + free( row ) ; + file_close( png ) ; + return NULL; + } + + if ( color == PNG_COLOR_TYPE_GRAY ) + { + for ( n = 0 ; n < height ; n++ ) rowpointers[n] = (( uint8_t* )bitmap->data ) + n * bitmap->pitch ; + png_read_image( png_ptr, rowpointers ) ; + + if ( depth == 8 ) + { + uint8_t colors[256 * 3]; + uint8_t * p = colors; + + for ( n = 0; n < 256 ; n++ ) + { + * p++ = n; + * p++ = n; + * p++ = n; + } + + bitmap->format->palette = pal_new_rgb(( uint8_t * )colors ); + pal_refresh( bitmap->format->palette ); + } + +// png_read_rows( png_ptr, rowpointers, 0, height ) ; + } + else if ( color == PNG_COLOR_TYPE_PALETTE ) + { + /* Read the color palette */ + + png_colorp png_palette = ( png_colorp ) png_malloc( png_ptr, 256 * sizeof( png_color ) ) ; + if ( !png_palette ) + { + bitmap_destroy( bitmap ); + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ) ; + free( rowpointers ) ; + free( row ) ; + file_close( png ) ; + return NULL; + } + png_get_PLTE( png_ptr, info_ptr, &png_palette, ( int * ) &n ) ; + + uint8_t colors[256 * 3]; + uint8_t * p = colors; + + for ( n = 0; n < 256 ; n++ ) + { + * p++ = png_palette[n].red; + * p++ = png_palette[n].green; + * p++ = png_palette[n].blue; + } + + bitmap->format->palette = pal_new_rgb(( uint8_t * )colors ); + pal_refresh( bitmap->format->palette ); + + if ( !sys_pixel_format->palette ) + { + sys_pixel_format->palette = pal_new( bitmap->format->palette ); +/* pal_use( bitmap->format->palette ); */ + palette_changed = 1 ; + } + + for ( n = 0 ; n < height ; n++ ) rowpointers[n] = (( uint8_t* )bitmap->data ) + n * bitmap->pitch ; + png_read_image( png_ptr, rowpointers ) ; + + /* If the depth is less than 8, expand the pixel values */ + + if ( depth == 4 ) + { + for ( n = 0; n < height; n++ ) + { + char * orig, * dest; + orig = ( char * ) ( rowpointers[n] ); + dest = orig + width - 1; + orig += ( width - 1 ) / 2; + + for ( x = width; x--; ) + { + *dest-- = ( *orig >> ((( 1 - ( x & 0x01 ) ) << 2 ) ) ) & 0x0F ; + if ( !( x & 0x01 ) ) orig--; + } + } + } + else if ( depth == 2 ) + { + for ( n = 0; n < height; n++ ) + { + char * orig, * dest; + orig = ( char * ) rowpointers[n]; + dest = orig + width - 1; + orig += ( width - 1 ) / 4; + + for ( x = width; x--; ) + { + *dest-- = ( *orig >> ((( 3 - ( x & 0x03 ) ) << 1 ) ) ) & 0x03 ; + if ( !( x & 0x03 ) ) orig--; + } + } + } + else if ( depth == 1 ) + { + for ( n = 0; n < height; n++ ) + { + char * orig, * dest; + orig = ( char * ) rowpointers[n]; + dest = orig + width - 1; + orig += ( width - 1 ) / 8; + + for ( x = width; x--; ) + { + *dest-- = ( *orig >> ( 7 - ( x & 0x07 ) ) ) & 0x01 ; + if ( !( x & 0x07 ) ) orig--; + } + } + } + } + else if ( depth == 8 && sys_pixel_format->depth != 16 ) + { +#if (PNG_LIBPNG_VER>=10500) + png_color_16p trans_color = 0; + png_get_tRNS( png_ptr, info_ptr, 0, 0, &trans_color); +#endif + + for ( n = 0 ; n < height ; n++ ) + { + rowpointers[0] = ( void * )row ; + png_read_rows( png_ptr, rowpointers, 0, 1 ) ; + + ptr32 = ( uint32_t* )((( uint8_t * )bitmap->data ) + n * bitmap->pitch ); + orig = row ; + for ( x = 0 ; x < width ; x++ ) + { + ARRANGE_DWORD( orig ); + *ptr32 = *orig ; + + /* DCelso */ +#if (PNG_LIBPNG_VER>=10500) + if (( color == PNG_COLOR_TYPE_RGB ) && ( png_get_bit_depth(png_ptr, info_ptr) == 24 ) && ( png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) )) +#else + if (( color == PNG_COLOR_TYPE_RGB ) && ( info_ptr->pixel_depth == 24 ) && ( info_ptr->valid & PNG_INFO_tRNS )) +#endif + { + uint8_t * ptr8 = (uint8_t *)orig; + if ( +#if (PNG_LIBPNG_VER>=10500) + ( ptr8[0] == trans_color->red ) && + ( ptr8[1] == trans_color->green ) && + ( ptr8[2] == trans_color->blue ) +#else + ( ptr8[0] == info_ptr->trans_values.red ) && + ( ptr8[1] == info_ptr->trans_values.green ) && + ( ptr8[2] == info_ptr->trans_values.blue ) +#endif + ) + *ptr32 = 0; + } + ptr32++, orig++ ; + } + } + } + else + { +#if (PNG_LIBPNG_VER>=10500) + png_color_16p trans_color = 0; + png_get_tRNS( png_ptr, info_ptr, 0, 0, &trans_color); +#endif + + Rshift = 8; + Gshift = 5; + Bshift = 3; + + Rmask = 0xF80000 ; // 3 + Gmask = 0x00FC00 ; // 2 + Bmask = 0x0000F8 ; // 3 + + for ( n = 0 ; n < height ; n++ ) + { + rowpointers[0] = ( void * )row ; + png_read_rows( png_ptr, rowpointers, 0, 1 ) ; + + ptr = ( uint16_t* )((( uint8_t * )bitmap->data ) + n * bitmap->pitch ); + orig = row ; + for ( x = 0 ; x < width ; x++ ) + { + ARRANGE_DWORD( orig ); + + if (( *orig ) & 0x80000000 ) + { + *ptr = (( *orig & Rmask ) >> Rshift ) | (( *orig & Gmask ) >> Gshift ) | (( *orig & Bmask ) >> Bshift ) ; + if ( !*ptr )( *ptr )++ ; + } + else + *ptr = 0 ; + + /* DCelso */ +#if (PNG_LIBPNG_VER>=10500) + if (( color == PNG_COLOR_TYPE_RGB ) && ( png_get_bit_depth(png_ptr, info_ptr) == 24 ) && ( png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) )) +#else + if (( color == PNG_COLOR_TYPE_RGB ) && ( info_ptr->pixel_depth == 24 ) && ( info_ptr->valid & PNG_INFO_tRNS )) +#endif + { + uint8_t * ptr8 = (uint8_t *)orig; + if ( +#if (PNG_LIBPNG_VER>=10500) + ( ptr8[0] == trans_color->red ) && + ( ptr8[1] == trans_color->green ) && + ( ptr8[2] == trans_color->blue ) +#else + ( ptr8[0] == info_ptr->trans_values.red ) && + ( ptr8[1] == info_ptr->trans_values.green ) && + ( ptr8[2] == info_ptr->trans_values.blue ) +#endif + ) + *ptr = 0; + } + ptr++, orig++ ; + } + } + } + + /* Fin */ + +#if (PNG_LIBPNG_VER>=10500) + if ( !setjmp( png_jmpbuf( png_ptr ) ) ) +#else + if ( !setjmp( png_ptr->jmpbuf ) ) +#endif + png_read_end( png_ptr, 0 ) ; + + bitmap->modified = 1 ; + + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ) ; + + free( rowpointers ) ; + free( row ) ; + file_close( png ) ; + + return bitmap ; +} + +/* + * FUNCTION : gr_save_png + * + * Save a GRAPH into a PNG file + * + * PARAMS : + * gr GRAPH with the image to save + * filename name for the file + * + * RETURN VALUE : + * 0 - FAILURE + * 1 - SUCCESS + * + */ + +int gr_save_png( GRAPH * gr, const char * filename ) +{ + if ( !gr ) return( 0 ) ; + + FILE * file = fopen( filename, "wb" ) ; + png_structp png_ptr ; + png_infop info_ptr ; + int k, i ; + png_bytep * rowpointers ; + png_colorp pal ; + uint32_t * data, * ptr ; + uint16_t * orig ; + uint32_t * orig32 ; + rgb_component * gpal = NULL; + + if ( !file ) return( 0 ) ; + + rowpointers = malloc( sizeof( png_bytep ) * gr->height ); + if ( !rowpointers ) + { + fclose( file ) ; + return 0 ; + } + + png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ) ; + if ( !png_ptr ) + { + free( rowpointers ) ; + fclose( file ) ; + return( 0 ) ; + } + + info_ptr = png_create_info_struct( png_ptr ) ; + if ( !info_ptr ) + { + png_destroy_write_struct( &png_ptr, NULL ) ; + free( rowpointers ) ; + fclose( file ) ; + return( 0 ) ; + } + + /* Error handling... */ + +#if (PNG_LIBPNG_VER>=10500) + if ( setjmp( png_jmpbuf( png_ptr ) ) ) +#else + if ( setjmp( png_ptr->jmpbuf ) ) +#endif + { + png_destroy_write_struct( &png_ptr, NULL ) ; + free( rowpointers ) ; + fclose( file ) ; + return( 0 ) ; + } + + png_init_io( png_ptr, file ) ; + + if ( gr->format->depth == 1 ) + { + png_set_IHDR( png_ptr, info_ptr, gr->width, + gr->height, 1, PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE ) ; + + png_write_info( png_ptr, info_ptr ) ; + + for ( k = 0 ; k < ( unsigned )gr->height ; k++ ) + rowpointers[k] = ( uint8_t * )gr->data + gr->pitch * k ; + + png_write_image( png_ptr, rowpointers ) ; + } + else + if ( gr->format->depth == 8 ) + { + /* 8 bits PNG file */ + png_set_IHDR( png_ptr, info_ptr, gr->width, + gr->height, 8, PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE ) ; + + +#if (PNG_LIBPNG_VER>=10500) + if (!( gr->info_flags & GI_NOCOLORKEY )) + { + /* this need test */ + png_color_16 trans_color; + png_byte trans = 1; + + trans_color.red = 0; + trans_color.green = 0; + trans_color.blue = 0; + trans_color.gray = 0; + + png_set_tRNS( png_ptr, info_ptr, &trans, 1, &trans_color ); + } +#else + /* DCelso */ + if (!( gr->info_flags & GI_NOCOLORKEY )) + { + uint8_t trans = 1; + info_ptr->num_trans = 1; + info_ptr->trans = &trans; + info_ptr->valid = info_ptr->valid | PNG_INFO_tRNS; + } + /* DCelso */ +#endif + pal = ( png_colorp ) png_malloc( png_ptr, 256 * sizeof( png_color ) ) ; + if ( !pal ) + { + png_destroy_write_struct( &png_ptr, NULL ) ; + free( rowpointers ) ; + fclose( file ) ; + return( 0 ) ; + } + + if ( gr->format->palette ) + gpal = gr->format->palette->rgb; + else if ( sys_pixel_format->palette ) + gpal = sys_pixel_format->palette->rgb; + else + gpal = ( rgb_component * )default_palette; + + /* Generate palette info */ + for ( k = 0 ; k < 256 ; k++ ) + { + pal[k].red = gpal[k].r ; + pal[k].green = gpal[k].g ; + pal[k].blue = gpal[k].b ; + } + png_set_PLTE( png_ptr, info_ptr, pal, 256 ) ; + png_write_info( png_ptr, info_ptr ) ; + + /* no need to rearrange data */ + for ( k = 0 ; k < ( unsigned )gr->height ; k++ ) + rowpointers[k] = ( uint8_t * )gr->data + gr->pitch * k ; + png_write_image( png_ptr, rowpointers ) ; + + /* Free allocated palette... */ + png_free( png_ptr, ( png_voidp ) pal ) ; +// info_ptr->palette = NULL ; + } + else + { + png_set_IHDR( png_ptr, info_ptr, gr->width, + gr->height, 8, PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE ) ; + + png_write_info( png_ptr, info_ptr ) ; + + data = malloc( gr->width * gr->height * 4 ) ; + if ( !data ) + { + png_destroy_write_struct( &png_ptr, NULL ) ; + free( rowpointers ) ; + fclose( file ) ; + return( 0 ) ; + } + + if ( gr->format->depth == 16 ) + { + for ( k = 0; k < ( unsigned )gr->height; k++ ) + { + ptr = data + gr->width * k ; /* uses dword for each pixel! */ + orig = ( uint16_t * )( gr->data + gr->pitch * k ) ; + rowpointers[k] = ( uint8_t * )ptr ; + for ( i = 0 ; i < ( unsigned )gr->width ; i++ ) + { + if ( *orig == 0 && !( gr->info_flags & GI_NOCOLORKEY ) ) + *ptr = 0x00000000 ; + else + { + *ptr = + (( *orig & 0xf800 ) >> 8 ) | + (( *orig & 0x07e0 ) << 5 ) | + (( *orig & 0x001f ) << 19 ) | + 0xFF000000 ; + /* Rearrange data */ + ARRANGE_DWORD( ptr ) ; + } + orig++ ; + ptr++ ; + } + } + } + else if ( gr->format->depth == 32 ) + { + for ( k = 0; k < ( unsigned )gr->height; k++ ) + { + ptr = data + gr->width * k ; /* uses dword for each pixel! */ + orig32 = ( uint32_t * )( gr->data + gr->pitch * k ) ; + rowpointers[k] = ( uint8_t * )ptr ; + for ( i = 0 ; i < ( unsigned )gr->width ; i++ ) + { + *ptr = + (( *orig32 & 0xff000000 ) ) | + (( *orig32 & 0x00ff0000 ) >> 16 ) | + (( *orig32 & 0x0000ff00 ) ) | + (( *orig32 & 0x000000ff ) << 16 ) ; + + /* Rearrange data */ + ARRANGE_DWORD( ptr ) ; + + orig32++ ; + ptr++ ; + } + } + } + png_write_image( png_ptr, rowpointers ) ; + free( data ) ; + } + + png_write_end( png_ptr, info_ptr ) ; + png_destroy_write_struct( &png_ptr, NULL ) ; + free( rowpointers ) ; + fclose( file ) ; + return ( 1 ) ; +} + +/* --------------------------------------------------------------------------- */ + +int gr_load_png( const char * mapname ) +{ + GRAPH * gr = gr_read_png( mapname ) ; + if ( !gr ) return 0 ; + gr->code = bitmap_next_code() ; + grlib_add_map( 0, gr ) ; + return gr->code ; +} + +/* --------------------------------------------------------------------------- */ |