/* * 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 #include #include #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" /* ----------------------------------------------------------------- */