diff options
Diffstat (limited to 'modules/mod_flic/mod_flic.c')
-rw-r--r-- | modules/mod_flic/mod_flic.c | 806 |
1 files changed, 806 insertions, 0 deletions
diff --git a/modules/mod_flic/mod_flic.c b/modules/mod_flic/mod_flic.c new file mode 100644 index 0000000..b5b84bc --- /dev/null +++ b/modules/mod_flic/mod_flic.c @@ -0,0 +1,806 @@ +/* + * 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 <string.h> + +#include <math.h> +#include <stdlib.h> + +#include "bgddl.h" +#include "dlvaracc.h" + +#include "libgrbase.h" +#include "libblit.h" +#include "librender.h" + +#include "mod_flic.h" + +/* --------------------------------------------------------------------- */ +/* Librería para reproducir ficheros FLI directamente desde el disco */ +/* --------------------------------------------------------------------- */ + +static FLIC * current_fli = 0 ; + +/* ----------------------------------------------------------------- */ + +static int info_fli( FLIC * flic, REGION * clip, int * z, int * drawme ) ; +static void draw_fli( FLIC * flic, REGION * clip ) ; +static void flic_destroy( FLIC * flic ) ; +static FLIC * flic_open( const char * filename ) ; +static FLIC * flic_do_delta( FLIC * flic ) ; +static FLIC * flic_do_delta_flc( FLIC * flic ) ; +static FLIC * flic_do_color( FLIC * flic ) ; +static FLIC * flic_do_brun( FLIC * flic ) ; +static FLIC * flic_do_chunk( FLIC * flic ) ; +static FLIC * flic_do_frame( FLIC * flic ) ; +static void flic_reset( FLIC * flic ) ; +static int modflic_start( INSTANCE * my, int * params ) ; +static int modflic_reset( INSTANCE * my, int * params ) ; +static int modflic_end( INSTANCE * my, int * params ) ; +static int modflic_frame( INSTANCE * my, int * params ) ; + +/* ----------------------------------------------------------------- */ + +static int info_fli( FLIC * flic, REGION * clip, int * z, int * drawme ) +{ + int changed ; + int ms ; + + * drawme = 1; + * z = flic->z; + + changed = + flic->saved_x != flic->x || + flic->saved_y != flic->y || + flic->saved_z != flic->z || + flic->saved_angle != flic->angle || + flic->saved_size != flic->size || + flic->saved_flags != flic->flags ; + + if ( changed ) + { + flic->saved_x = flic->x ; + flic->saved_y = flic->y ; + flic->saved_z = flic->z ; + flic->saved_angle = flic->angle; + flic->saved_size = flic->size ; + flic->saved_flags = flic->flags; + } + + ms = SDL_GetTicks() ; + if ( flic->last_frame_ms + flic->speed_ms < ms && !flic->finished ) + changed |= ( flic_do_frame( flic ) != NULL ) ; + + if ( !changed ) return 0; + + if ( flic->angle || flic->size != 100 ) + { + gr_get_bbox( clip, + 0, + flic->x + flic->bitmap->width / 2, + flic->y + flic->bitmap->height / 2, + flic->flags, + flic->angle, + flic->size, + flic->size, + flic->bitmap + ) ; + } + else + { + clip->x = flic->x ; + clip->x2 = flic->x + flic->bitmap->width ; + clip->y = flic->y ; + clip->y2 = flic->y + flic->bitmap->height ; + } + + return 1; +} + +static void draw_fli( FLIC * flic, REGION * clip ) +{ + if ( flic->angle || flic->size != 100 ) + gr_rotated_blit( 0, + clip, + flic->x + flic->bitmap->width / 2, + flic->y + flic->bitmap->height / 2, + flic->flags, + flic->angle, + flic->size, + flic->size, + flic->bitmap ) ; + else + gr_blit( 0, + clip, + flic->x + flic->bitmap->width / 2, + flic->y + flic->bitmap->height / 2, + flic->flags, + flic->bitmap ) ; +} + +/* --------------------------------------------------------------------- */ + +static void flic_destroy( FLIC * flic ) +{ + if ( !flic ) return ; + + file_close( flic->fp ) ; + if ( flic->objid ) gr_destroy_object( flic->objid ); + if ( flic->bitmap ) bitmap_destroy( flic->bitmap ) ; + if ( flic->frame ) free( flic->frame ) ; + free( flic ) ; +} + +static FLIC * flic_open( const char * filename ) +{ + FLIC * flic ; + + flic = ( FLIC * ) malloc( sizeof( FLIC ) ) ; + if ( !flic ) return 0 ; + + flic->objid = 0; + + flic->fp = file_open( filename, "rb" ) ; + if ( !flic->fp ) + { + free( flic ) ; + return 0 ; + } + flic->frame_reserved = 8192 ; + flic->frame = ( FLIC_FRAME * ) malloc( 8192 ) ; + if ( !flic->frame ) + { + flic_destroy( flic ) ; + return 0 ; + } + + if ( !file_read( flic->fp, &flic->header, sizeof( FLIC_HEADER ) ) ) + { + flic_destroy( flic ) ; + return 0 ; + } + + if ( flic->header.type != 0xAF11 && flic->header.type != 0xAF12 ) + { + /* Tipo de FLIC no reconocido */ + flic_destroy( flic ) ; + return 0 ; + } + + flic->bitmap = bitmap_new( 0, flic->header.width, flic->header.height, 8 ) ; + if ( !flic->bitmap ) + { + /* Tamaño incorrecto */ + flic_destroy( flic ) ; + return 0 ; + } + + if ( !flic->header.oframe1 ) flic->header.oframe1 = file_pos( flic->fp ) ; + + flic->current_frame = 0 ; + flic->finished = 0 ; + flic->last_frame_ms = SDL_GetTicks() ; + + if ( flic->header.type == 0xAF11 ) + flic->speed_ms = ( int )(( 1000.0F / 70.0F ) * flic->header.speed ) ; + else + flic->speed_ms = flic->header.speed ; + + flic->objid = gr_new_object( 0, info_fli, draw_fli, flic ); + + return flic ; +} + +static FLIC * flic_do_delta( FLIC * flic ) +{ + GRAPH * bitmap = flic->bitmap ; + int first_line, line_count ; + uint8_t * ptr, * optr, * loptr, packet_count ; + int size; + + first_line = flic->chunk->delta_fli.first_line ; + line_count = flic->chunk->delta_fli.line_count ; + ptr = flic->chunk->delta_fli.data ; + + loptr = ( uint8_t * )bitmap->data + bitmap->pitch * first_line ; + + while ( line_count-- > 0 ) + { + optr = loptr ; + loptr += bitmap->pitch ; + packet_count = *ptr++ ; + + while ( packet_count-- ) + { + optr += *ptr++ ; + size = *( Sint8 * )ptr++ ; + if ( size > 0 ) + { + memcpy( optr, ptr, size ) ; + ptr += size ; + } + else if ( size < 0 ) + { + size = -size ; + memset( optr, *ptr++, size ) ; + } + optr += size ; + } + } + + return flic ; +} + +static FLIC * flic_do_delta_flc( FLIC * flic ) +{ + GRAPH * bitmap = flic->bitmap ; + int line_count ; + uint16_t * ptr, opcode ; + uint8_t * optr, * loptr ; + Sint8 data_count ; + + ptr = ( uint16_t * )flic->chunk->raw.data ; + + line_count = *ptr++ ; + + optr = bitmap->data ; + + while ( line_count > 0 ) + { + opcode = *ptr++ ; + + switch ( opcode & 0xC000 ) + { + case 0x0000: + loptr = optr ; + while ( opcode-- > 0 ) + { + optr += *( uint8_t * )ptr ; + data_count = *(( Sint8 * )ptr + 1 ) ; + ptr++ ; + + if ( data_count > 0 ) + { + memcpy( optr, ptr, ( int )data_count * 2 ) ; + ptr += data_count ; + optr += data_count * 2 ; + } + else if ( data_count < 0 ) + { + data_count = -data_count ; + while ( data_count-- ) + { + *optr++ = ( *ptr & 0xFF ) ; + *optr++ = ( *ptr >> 8 ) ; + } + ptr++ ; + } + } + + optr = loptr ; + optr += bitmap->width ; + line_count-- ; + break ; + + case 0x4000: + return 0 ; + + case 0x8000: + optr[bitmap->width-1] = ( opcode & 0xFF ) ; + break ; + + case 0xC000: + optr += bitmap->pitch * -( Sint16 )opcode; + break ; + } + } + + return flic ; +} + +static FLIC * flic_do_color( FLIC * flic ) +{ + uint8_t * ptr ; + int packet_count ; + int copy_count ; + rgb_component * palette ; + rgb_component * color; + PALETTE * pal ; + + if ( sys_pixel_format->depth == 8 ) + { + if ( ! sys_pixel_format->palette ) + { + sys_pixel_format->palette = pal_new( NULL ) ; + palette_changed = 1 ; + } + pal = sys_pixel_format->palette ; + } + else + { + if ( !flic->bitmap->format->palette ) + { + flic->bitmap->format->palette = pal_new( NULL ) ; + palette_changed = 1 ; + } + pal = flic->bitmap->format->palette ; + } + + palette = pal->rgb; + + ptr = flic->chunk->raw.data ; + + packet_count = *( uint16_t * )ptr ; + ptr += 2 ; + + while ( packet_count-- > 0 ) + { + color = &palette[*ptr++] ; + copy_count = *ptr++ ; + if ( copy_count < 1 ) copy_count = 256 ; + + if ( flic->chunk->header.type == CHUNK_COLOR_64 ) + { + while ( copy_count-- ) + { + color->r = ( *ptr++ << 2 ) ; + color->g = ( *ptr++ << 2 ) ; + color->b = ( *ptr++ << 2 ) ; + color++ ; + } + } + else + { + while ( copy_count-- ) + { + color->r = *ptr++ ; + color->g = *ptr++ ; + color->b = *ptr++ ; + color++ ; + } + } + } + + pal_refresh( pal ); + + return flic ; +} + +static FLIC * flic_do_brun( FLIC * flic ) +{ + GRAPH * bitmap = flic->bitmap ; + int line_count ; + uint8_t * ptr, * optr, * loptr ; + uint16_t remaining_width ; + int size; + + ptr = flic->chunk->raw.data ; + loptr = bitmap->data ; + line_count = bitmap->height ; + + while ( line_count-- ) + { + optr = loptr; + loptr += bitmap->pitch ; + ptr++ ; + remaining_width = bitmap->width ; + + while ( remaining_width > 0 ) + { + size = *( Sint8 * )ptr++; + if ( size < 0 ) + { + size = -size; + memcpy( optr, ptr, size ) ; + ptr += size ; + } + else if ( size > 0 ) + { + memset( optr, *ptr++, size ) ; + } + optr += size ; + remaining_width -= size ; + } + } + + return flic ; +} + +static FLIC * flic_do_chunk( FLIC * flic ) +{ + uint32_t y; + uint8_t * data ; + uint8_t * rawdata ; + + /* Procesa el contenido del chunk actual */ + + switch ( flic->chunk->header.type ) + { + case CHUNK_BLACK: + data = ( uint8_t * )flic->bitmap->data ; + for ( y = flic->bitmap->height ; y-- ; ) + { + memset( data, 0, flic->bitmap->pitch ) ; + data += flic->bitmap->pitch ; + } + break ; + + case CHUNK_FLI_COPY: + data = ( uint8_t * )flic->bitmap->data ; + rawdata = ( uint8_t * )flic->chunk->raw.data ; + for ( y = flic->bitmap->height ; y-- ; ) + { + memcpy( data, rawdata, flic->bitmap->width ) ; + data += flic->bitmap->pitch ; + rawdata += flic->bitmap->width ; + } + break ; + + case CHUNK_DELTA_FLI: + if ( !flic_do_delta( flic ) ) return 0 ; + break ; + + case CHUNK_DELTA_FLC: + if ( !flic_do_delta_flc( flic ) ) return 0 ; + break ; + + case CHUNK_BYTE_RUN: + if ( !flic_do_brun( flic ) ) return 0 ; + break ; + + case CHUNK_COLOR_256: + case CHUNK_COLOR_64: + if ( !flic_do_color( flic ) ) return 0 ; + break ; + + case CHUNK_STAMP: + break ; + + default: + /* Tipo de chunk desconocido */ + return 0 ; + } + + return flic ; +} + +static FLIC * flic_do_frame( FLIC * flic ) +{ + int chunkno = 0 ; + + /* Cuenta el frame y vuelve al inicio si es necesario */ + + flic->current_frame++ ; + + if ( flic->current_frame >= flic->header.frames ) + { + file_seek( flic->fp, flic->header.oframe1, SEEK_SET ) ; + flic->current_frame = 1 ; + flic->finished = 1 ; + return flic ; + } + + do + { + /* Recupera información del siguiente chunk del fichero */ + + if ( !file_read( flic->fp, flic->frame, sizeof( FLIC_FRAME ) ) ) return 0 ; + + /* Tipo de frame incorrecto */ + if ( flic->frame->type != CHUNK_FRAME && flic->frame->type != CHUNK_PREFIX ) return 0 ; + + /* Fichero corrupto */ + if ( flic->frame->size < sizeof( FLIC_FRAME ) ) return 0; + + /* Reserva la memoria necesaria y carga el chunk */ + + if ( flic->frame_reserved < flic->frame->size ) + { + flic->frame_reserved = flic->frame->size ; + flic->frame = ( FLIC_FRAME * ) realloc( flic->frame, flic->frame_reserved ) ; + + /* Error: sin memoria */ + if ( !flic->frame ) return 0 ; + } + + /* If it's a prefix frame, skip it. */ + + if ( flic->frame->size > sizeof( FLIC_FRAME ) ) + if ( !file_read( flic->fp, &flic->frame[1], flic->frame->size - sizeof( FLIC_FRAME ) ) ) return 0 ; + + } + while ( flic->frame->type != CHUNK_FRAME ) ; + + /* Procesa cada sub-chunk */ + + flic->chunk = ( FLIC_CHUNK * ) & flic->frame[1] ; + + for ( chunkno = 0 ; chunkno < flic->frame->chunks ; chunkno++ ) + { + if ( !flic_do_chunk( flic ) ) return 0 ; + flic->chunk = ( FLIC_CHUNK * )((( uint8_t * )flic->chunk ) + flic->chunk->header.size ) ; + } + + flic->last_frame_ms += flic->speed_ms ; + return flic ; +} + +static void flic_reset( FLIC * flic ) +{ + flic->current_frame = 0 ; + flic->finished = 0 ; + file_seek( flic->fp, flic->header.oframe1, SEEK_SET ) ; +} + +/* ----------------------------------------------------------------- */ +/* Reproducción de FLI */ + +/* + * FUNCTION : modflic_start + * + * Load & start playing a FLI/FLC animation + * + * PARAMS: + * + * file : filename/path for the FLI/FLC file + * x,y : screen position + * + */ + +static int modflic_start( INSTANCE * my, int * params ) +{ + const char * str = string_get( params[0] ) ; + if ( !str ) return 0 ; + + if ( current_fli ) flic_destroy( current_fli ) ; + + current_fli = flic_open( str ) ; + + string_discard( params[0] ) ; + + if ( current_fli ) + { + current_fli->x = params[1] ; + current_fli->y = params[2] ; + current_fli->z = 0; + current_fli->angle = 0; + current_fli->size = 100; + current_fli->flags = 0; + + return current_fli->header.frames ; + } + + return 0 ; +} + +/* + * FUNCTION : modflic_reset + * + * Reset current FLI/FLC animation to frame 0 + * + * PARAMS: + * + * No params + * + */ + +static int modflic_reset( INSTANCE * my, int * params ) +{ + if ( current_fli ) flic_reset( current_fli ) ; + return 1 ; +} + +/* + * FUNCTION : modflic_end + * + * Stop current FLI/FLC animation + * + * PARAMS: + * + * No params + * + */ + +static int modflic_end( INSTANCE * my, int * params ) +{ + if ( current_fli ) + { + flic_destroy( current_fli ) ; + current_fli = 0 ; + } + return 1 ; +} + +/* + * FUNCTION : modflic_frame + * + * Check status for the current FLI/FLC animation + * + * RETURN VALUE: + * + * Current frame or 0 if animation has ended + * + * PARAMS: + * + * No params + * + */ + +static int modflic_frame( INSTANCE * my, int * params ) +{ + if ( current_fli ) return current_fli->finished ? 0 : current_fli->current_frame ; + return 0 ; +} + +/* --------------------------------------------------------------------------- */ + +static int modflic_startx1( INSTANCE * my, int * params ) +{ + FLIC * flic ; + const char * str = string_get( params[0] ) ; + if ( !str ) return 0 ; + + flic = flic_open( str ) ; + + string_discard( params[0] ) ; + + if ( flic ) + { + flic->x = params[1] ; + flic->y = params[2] ; + flic->z = 0 ; + flic->angle = 0; + flic->size = 100; + flic->flags = 0; + + return ( int ) flic ; + } + + return 0 ; +} + +static int modflic_startx2( INSTANCE * my, int * params ) +{ + FLIC * flic ; + const char * str = string_get( params[0] ) ; + if ( !str ) return 0 ; + + flic = flic_open( str ) ; + + string_discard( params[0] ) ; + + if ( flic ) + { + flic->x = params[1] ; + flic->y = params[2] ; + flic->z = params[3] ; + flic->angle = params[4]; + flic->size = params[5]; + flic->flags = params[6]; + + return ( int ) flic ; + } + + return 0 ; +} + +static int modflic_resetx( INSTANCE * my, int * params ) +{ + flic_reset(( FLIC * ) params[0] ) ; + return 1 ; +} + +static int modflic_endx( INSTANCE * my, int * params ) +{ + flic_destroy((( FLIC * ) params[0] ) ) ; + return 1 ; +} + +static int modflic_framex( INSTANCE * my, int * params ) +{ + return (( FLIC * ) params[0] )->finished ? 0 : (( FLIC * ) params[0] )->current_frame ; +} + +static int modflic_params( INSTANCE * my, int * params ) +{ + FLIC * flic = ( FLIC * ) params[0] ; + + flic->x = params[1] ; + flic->y = params[2] ; + flic->z = params[3] ; + flic->angle = params[4]; + flic->size = params[5]; + flic->flags = params[6]; + + return 1 ; +} + +static int modflic_move( INSTANCE * my, int * params ) +{ + FLIC * flic = ( FLIC * ) params[0] ; + + flic->x = params[1] ; + flic->y = params[2] ; + + return 1 ; +} + +static int modflic_z( INSTANCE * my, int * params ) +{ + (( FLIC * ) params[0] )->z = params[1] ; + + return 1 ; +} + +static int modflic_angle( INSTANCE * my, int * params ) +{ + (( FLIC * ) params[0] )->angle = params[1] ; + + return 1 ; +} + +static int modflic_size( INSTANCE * my, int * params ) +{ + (( FLIC * ) params[0] )->size = params[1] ; + + return 1 ; +} + +static int modflic_flags( INSTANCE * my, int * params ) +{ + (( FLIC * ) params[0] )->flags = params[1] ; + + return 1 ; +} + +static int modflic_getinfo( INSTANCE * my, int * params ) +{ + FLIC * flic = ( FLIC * ) params[0] ; + + if ((( int * ) params[1] ) ) *(( int * ) params[1] ) = flic->x ; + if ((( int * ) params[2] ) ) *(( int * ) params[2] ) = flic->y ; + if ((( int * ) params[3] ) ) *(( int * ) params[3] ) = flic->z ; + if ((( int * ) params[4] ) ) *(( int * ) params[4] ) = flic->angle ; + if ((( int * ) params[5] ) ) *(( int * ) params[5] ) = flic->size ; + if ((( int * ) params[6] ) ) *(( int * ) params[6] ) = flic->flags ; + if ((( int * ) params[7] ) ) *(( int * ) params[7] ) = flic->header.frames ; + if ((( int * ) params[8] ) ) *(( int * ) params[8] ) = flic->header.width ; + if ((( int * ) params[9] ) ) *(( int * ) params[9] ) = flic->header.height ; + + return 1 ; +} + +/* ----------------------------------------------------------------- */ +/* exports */ +/* ----------------------------------------------------------------- */ + +#include "mod_flic_exports.h" + +/* ----------------------------------------------------------------- */ |