/* * 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 "libgrbase.h" #include "bgddl.h" #include "dlvaracc.h" /* --------------------------------------------------------------------------- */ /* Conversion tables - used by 16 bits conversions - 256K */ static uint16_t * convert565ToScreen = NULL ; static uint16_t * convertScreenTo565 = NULL ; static int conversion_tables_ok = 0 ; /* Alpha multiplication tables - multiply a color by its alpha. * There will be less than 256 levels */ static uint16_t * alpha16[ 256 ]; static uint8_t * alpha8[ 256 ]; static int alpha16_tables_ok = 0 ; static int alpha8_tables_ok = 0 ; /* --------------------------------------------------------------------------- */ /* used for variable access */ /* --------------------------------------------------------------------------- */ enum { ALPHA_STEPS = 0 }; /* --------------------------------------------------------------------------- */ /* Son las variables que se desea acceder. */ /* El interprete completa esta estructura, si la variable existe. */ /* (usada en tiempo de ejecucion) */ DLVARFIXUP __bgdexport( libgrbase, globals_fixup )[] = { /* Nombre de variable global, puntero al dato, tamaño del elemento, cantidad de elementos */ { "alpha_steps" , NULL, -1, -1 }, { NULL , NULL, -1, -1 } }; /* --------------------------------------------------------------------------- */ /* * FUNCTION : init_alpha16_tables * * Init the 16 bit alpha tables (create as many tables as the parameter) * Each alpha table has a 128K memory footprint. Having many alpha tables * provides more transparency values. * * PARAMS : * count Number of tables * * RETURN VALUE : * None * */ static void init_alpha16_tables( int count ) { int i, color, inc, next = 0, factor; uint16_t * table16 = NULL; if ( count <= 0 ) count = 1; if ( count > 128 ) count = 128; if ( alpha16_tables_ok == count ) return ; inc = 256 / count; /* Destroy existing tables */ if ( alpha16_tables_ok ) { for ( table16 = NULL, i = 0 ; i < 256 ; i++ ) { if ( alpha16[ i ] != table16 ) { table16 = alpha16[ i ]; free( table16 ); } alpha16[ i ] = NULL; } } /* Make new ones */ for ( i = 0 ; i < 256 ; i++ ) { if ( i == next ) { table16 = malloc( 131072 ); factor = next + inc / 2; next += inc; if ( factor > 255 ) factor = 256; for ( color = 0 ; color < 65536 ; color++ ) { int r = (( color & sys_pixel_format->Rmask ) >> sys_pixel_format->Rshift << sys_pixel_format->Rloss ) ; int g = (( color & sys_pixel_format->Gmask ) >> sys_pixel_format->Gshift << sys_pixel_format->Gloss ) ; int b = (( color & sys_pixel_format->Bmask ) >> sys_pixel_format->Bshift << sys_pixel_format->Bloss ) ; table16[ color ] = (((( r * factor ) >> 8 ) >> sys_pixel_format->Rloss ) << sys_pixel_format->Rshift ) | (((( g * factor ) >> 8 ) >> sys_pixel_format->Gloss ) << sys_pixel_format->Gshift ) | (((( b * factor ) >> 8 ) >> sys_pixel_format->Bloss ) << sys_pixel_format->Bshift ) ; } } alpha16[ i ] = table16; } alpha16_tables_ok = count; } /* --------------------------------------------------------------------------- */ /* * FUNCTION : init_alpha8_tables * * Init the 8 bit alpha tables (create as many tables as the parameter) * Each alpha table has a 64K memory footprint. Having many alpha tables * provides more transparency values. Those tables should be updated * when the palette changes. * * PARAMS : * count Number of tables * * RETURN VALUE : * None * */ static void init_alpha8_tables( int count ) { int i, color, color2, inc, next = 0, factor; uint8_t * table8 = NULL; rgb_component * rgb ; if ( count <= 0 ) count = 1; if ( count > 128 ) count = 128; if ( alpha16_tables_ok == count ) return ; inc = 256 / count; /* Destroy existing tables */ if ( alpha8_tables_ok ) { for ( table8 = NULL, i = 0; i < 256; i++ ) { if ( alpha8[ i ] != table8 ) { table8 = alpha8[ i ]; free( table8 ); } alpha8[ i ] = NULL; } } /* Make new ones */ if ( !sys_pixel_format->palette ) rgb = ( rgb_component * ) default_palette; else rgb = sys_pixel_format->palette->rgb ; for ( i = 0; i < 256; i++ ) { if ( i == next ) { table8 = malloc( 65536 ); factor = next + inc / 2; next += inc; if ( factor > 255 ) factor = 255; for ( color = 0; color < 256; color++ ) { for ( color2 = 0; color2 < 256; color2++ ) { int r = ( rgb[ color ].r * factor + rgb[ color2 ].r * ( 255 - factor ) ) >> 8 ; int g = ( rgb[ color ].g * factor + rgb[ color2 ].g * ( 255 - factor ) ) >> 8 ; int b = ( rgb[ color ].b * factor + rgb[ color2 ].b * ( 255 - factor ) ) >> 8 ; table8[( color << 8 ) + color2 ] = gr_find_nearest_color( r, g, b ); } table8[ color ] = color; } } alpha8[ i ] = table8; } alpha8_tables_ok = count; } /* --------------------------------------------------------------------------- */ /* * FUNCTION : init_conversion_tables * * Static routine used to initialize the 16 bits conversion * tables (this only needs to be done once) * * PARAMS : * None * * RETURN VALUE : * None * */ static void init_conversion_tables() { uint8_t r, g, b ; int n ; /* Alloc space for the lookup tables */ convert565ToScreen = ( uint16_t * ) malloc( sizeof( uint16_t ) * 65536 ); if ( !convert565ToScreen ) return ; convertScreenTo565 = ( uint16_t * ) malloc( sizeof( uint16_t ) * 65536 ); if ( !convertScreenTo565 ) // No memory { free( convert565ToScreen ); return ; } /* Special case if screen already in 565 format */ if ( sys_pixel_format->Rmask == 0xF800 && sys_pixel_format->Gmask == 0x07E0 && sys_pixel_format->Bmask == 0x001F ) { for ( n = 0; n < 65536; n++ ) { convert565ToScreen[ n ] = n; convertScreenTo565[ n ] = n; } return ; } /* Create a fast lookup array */ for ( n = 0; n < 65536; n++ ) { /* Calculate conversion from 565 to screen format */ r = (( n >> 8 ) & 0xF8 ) >> sys_pixel_format->Rloss ; g = (( n >> 3 ) & 0xFC ) >> sys_pixel_format->Gloss ; b = (( n << 3 ) & 0xF8 ) >> sys_pixel_format->Bloss ; convert565ToScreen[ n ] = ( r << sys_pixel_format->Rshift ) | ( g << sys_pixel_format->Gshift ) | ( b << sys_pixel_format->Bshift ) ; /* Calculate conversion from 565 to screen format */ r = ((( n & sys_pixel_format->Rmask ) >> sys_pixel_format->Rshift ) << sys_pixel_format->Rloss ); g = ((( n & sys_pixel_format->Gmask ) >> sys_pixel_format->Gshift ) << sys_pixel_format->Gloss ); b = ((( n & sys_pixel_format->Bmask ) >> sys_pixel_format->Bshift ) << sys_pixel_format->Bloss ); convertScreenTo565[ n ] = (( r & 0xF8 ) << 8 ) | (( g & 0xFC ) << 3 ) | (( b & 0xF8 ) >> 3 ) ; } conversion_tables_ok = 1; } /* --------------------------------------------------------------------------- */ /* * FUNCTION : gr_convert16_565ToScreen * * Convert a sequence of 16 bits pixels from 5:6:5 format to * the format used by the screen (usually 5:5:5 or 5:6:5) * * PARAMS : * ptr Pointer to the first pixel * len Number of pixels (not bytes!) * * RETURN VALUE : * None * */ void gr_convert16_565ToScreen( uint16_t * ptr, int len ) { if ( !conversion_tables_ok ) init_conversion_tables(); while ( len-- ) { *ptr = convert565ToScreen[ *ptr ] ; ptr++; } } /* --------------------------------------------------------------------------- */ /* * FUNCTION : gr_convert16_ScreenTo565 * * Convert a sequence of 16 bits pixels in screen format * (usually 5:5:5 or 5:6:5) to the 5:6:5 format used to * store 16 bits pixel values to files in disk * * PARAMS : * ptr Pointer to the first pixel * len Number of pixels (not bytes!) * * RETURN VALUE : * None * */ void gr_convert16_ScreenTo565( uint16_t * ptr, int len ) { if ( !conversion_tables_ok ) init_conversion_tables(); while ( len-- ) { *ptr = convertScreenTo565[ *ptr ] ; ptr++; } } /* --------------------------------------------------------------------------- */ /* * FUNCTION : gr_fade16 * * Fade a 16-bit graphic a given ammount. Fading values are given in percent * (0% = black, 100% = original color, 200% = full color value) * * PARAMS : * graph Pointer to the graphic object * r Percent of Red component * g Percent of Green component * b Percent of Blue component * * RETURN VALUE : * None * */ void gr_fade16( GRAPH * graph, int r, int g, int b ) { uint32_t Rtable[ 32 ]; uint32_t Gtable[ 32 ]; uint32_t Btable[ 32 ]; uint32_t x, y; uint32_t Rmask; uint32_t Rshift; uint32_t Gmask; uint32_t Gshift; uint32_t Bmask; uint32_t Bshift; for ( x = 0 ; x < 32 ; x++ ) { int c = 8 * x + 7; if ( r <= 100 ) Rtable[ x ] = ( c * r / 100 ) >> sys_pixel_format->Rloss << sys_pixel_format->Rshift; else Rtable[ x ] = ( c + ( 255 - c ) * ( r - 100 ) / 100 ) >> sys_pixel_format->Rloss << sys_pixel_format->Rshift; if ( g <= 100 ) Gtable[ x ] = ( c * g / 100 ) >> sys_pixel_format->Gloss << sys_pixel_format->Gshift; else Gtable[ x ] = ( c + ( 255 - c ) * ( g - 100 ) / 100 ) >> sys_pixel_format->Gloss << sys_pixel_format->Gshift; if ( b <= 100 ) Btable[ x ] = ( c * b / 100 ) >> sys_pixel_format->Bloss << sys_pixel_format->Bshift; else Btable[ x ] = ( c + ( 255 - c ) * ( b - 100 ) / 100 ) >> sys_pixel_format->Bloss << sys_pixel_format->Bshift; } Rmask = sys_pixel_format->Rmask; Gmask = sys_pixel_format->Gmask; Bmask = sys_pixel_format->Bmask; Rshift = sys_pixel_format->Rshift - sys_pixel_format->Rloss + 3; Gshift = sys_pixel_format->Gshift - sys_pixel_format->Gloss + 3; Bshift = sys_pixel_format->Bshift - sys_pixel_format->Bloss + 3; if ( graph->format->depth == 16 ) { char * p = graph->data ; uint16_t * ptr ; for ( y = 0 ; y < graph->height ; y++ ) { ptr = ( uint16_t * ) p ; for ( x = 0 ; x < graph->width ; x++, ptr++ ) { *ptr = ( Rtable[(( *ptr & Rmask ) >> Rshift )] | Gtable[(( *ptr & Gmask ) >> Gshift )] | Btable[(( *ptr & Bmask ) >> Bshift )] ); } p += graph->pitch ; } } else if ( graph->format->depth == 32 ) { char * p = graph->data ; uint32_t * ptr ; for ( y = 0 ; y < graph->height ; y++ ) { ptr = ( uint32_t * ) p ; for ( x = 0 ; x < graph->width ; x++, ptr++ ) { *ptr = ( Rtable[(( *ptr & Rmask ) >> Rshift )] | Gtable[(( *ptr & Gmask ) >> Gshift )] | Btable[(( *ptr & Bmask ) >> Bshift )] ); } p += graph->pitch ; } } } /* --------------------------------------------------------------------------- */ /* * FUNCTION : gr_alpha16 * * Get an alpha multiplication table (a table that, given a 16 bit color, * returns the color multiplied by the alpha value) * * PARAMS : * alpha Alpha value for the requested table * * RETURN VALUE : * None * */ uint16_t * gr_alpha16( int alpha ) { if ( !alpha16_tables_ok ) init_alpha16_tables( GLODWORD( libgrbase, ALPHA_STEPS ) ); return alpha16[ alpha ]; } /* --------------------------------------------------------------------------- */ /* * FUNCTION : gr_alpha8 * * Get an alpha translation table (a table that, given two 8 bit color, * returns the composite color given the alpha value) * * PARAMS : * alpha Alpha value for the requested table * * RETURN VALUE : * None * */ uint8_t * gr_alpha8( int alpha ) { if ( !alpha8_tables_ok ) init_alpha8_tables( GLODWORD( libgrbase, ALPHA_STEPS ) ); return ( uint8_t * ) alpha8[ alpha ]; } /* --------------------------------------------------------------------------- */