diff options
Diffstat (limited to 'modules/libgrbase/g_bitmap.c')
| -rw-r--r-- | modules/libgrbase/g_bitmap.c | 463 | 
1 files changed, 463 insertions, 0 deletions
| diff --git a/modules/libgrbase/g_bitmap.c b/modules/libgrbase/g_bitmap.c new file mode 100644 index 0000000..db88afb --- /dev/null +++ b/modules/libgrbase/g_bitmap.c @@ -0,0 +1,463 @@ +/* + *  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 <stdlib.h> +#include <string.h> + +#include "libgrbase.h" +#include "bitwise_map.h" + +/* --------------------------------------------------------------------------- */ + +uint32_t * map_code_bmp = NULL ; +int map_code_allocated = 0 ; +int map_code_last = 0; + +/* --------------------------------------------------------------------------- */ + +PIXEL_FORMAT * bitmap_create_format( int bpp ) +{ +    PIXEL_FORMAT *format; + +    /* Allocate an empty pixel format structure */ +    format = malloc( sizeof( *format ) ); +    if ( !format ) return( NULL ); + +    /* Set up the format */ + +    format->palette = NULL; +    format->depth = bpp; +    format->depthb = ( bpp + 7 ) / 8; + +    if ( bpp == 32 ) +    { +        format->Aloss = 0; +        format->Rloss = 0; +        format->Gloss = 0; +        format->Bloss = 0; + +        format->Ashift = 24; +        format->Rshift = 16; +        format->Gshift = 8; +        format->Bshift = 0; + +        format->Amask = 0xFF000000; +        format->Rmask = 0x00FF0000; +        format->Gmask = 0x0000FF00; +        format->Bmask = 0x000000FF; +    } +    else if ( bpp > 8 ) +    { +        /* R-G-B */ +        if ( bpp > 24 ) bpp = 24; + +        format->Rloss = 8 - ( bpp / 3 ); +        format->Gloss = 8 - ( bpp / 3 ) - ( bpp % 3 ); +        format->Bloss = 8 - ( bpp / 3 ); + +        format->Rshift = (( bpp / 3 ) + ( bpp % 3 ) ) + ( bpp / 3 ); +        format->Gshift = ( bpp / 3 ); +        format->Bshift = 0; + +        format->Rmask = (( 0xFF >> format->Rloss ) << format->Rshift ); +        format->Gmask = (( 0xFF >> format->Gloss ) << format->Gshift ); +        format->Bmask = (( 0xFF >> format->Bloss ) << format->Bshift ); +    } +    else +    { +        format->Rloss = 8; +        format->Gloss = 8; +        format->Bloss = 8; +        format->Aloss = 8; + +        format->Rshift = 0; +        format->Gshift = 0; +        format->Bshift = 0; +        format->Ashift = 0; + +        format->Rmask = 0; +        format->Gmask = 0; +        format->Bmask = 0; +        format->Amask = 0; +    } + +    return( format ); +} + +/* --------------------------------------------------------------------------- */ + +GRAPH * bitmap_new_ex( int code, int w, int h, int depth, void * data, int pitch ) +{ +    GRAPH * gr ; +    int wb ; + +    if ( w < 1 || h < 1 ) return NULL; + +    /* Create and fill the struct */ + +    gr = ( GRAPH * ) malloc( sizeof( GRAPH ) ) ; +    if ( !gr ) return NULL; // sin memoria + +    /* Calculate the row size (dword-aligned) */ + +    wb = w * depth / 8; +    if (( wb * 8 / depth ) < w ) wb++; + +    gr->data = data ; + +    gr->width = w ; +    gr->height = h ; + +    gr->format = bitmap_create_format( depth ) ; + +    gr->pitch = pitch ; +    gr->widthb = wb ; + +    gr->code = code ; +    gr->name[ 0 ] = '\0'; + +    gr->ncpoints = 0; +    gr->cpoints = NULL ; + +    gr->format->palette = NULL ; + +    gr->blend_table = NULL ; + +    gr->modified = 0; +    gr->info_flags = GI_EXTERNAL_DATA ; + +    return gr ; +} + +/* --------------------------------------------------------------------------- */ + +GRAPH * bitmap_new( int code, int w, int h, int depth ) +{ +    GRAPH * gr ; +    int bytesPerRow, wb ; + +    if ( w < 1 || h < 1 ) return NULL; + +    /* Create and fill the struct */ + +    gr = ( GRAPH * ) malloc( sizeof( GRAPH ) ) ; +    if ( !gr ) return NULL; // sin memoria + +    /* Calculate the row size (dword-aligned) */ + +    wb = w * depth / 8; +    if (( wb * 8 / depth ) < w ) wb++; + +    bytesPerRow = wb; +    if ( bytesPerRow & 0x03 ) bytesPerRow = ( bytesPerRow & ~3 ) + 4; + +    gr->data = ( char * ) malloc( h * bytesPerRow ) ; +    if ( !gr->data )   // Sin memoria +    { +        free( gr ); +        return NULL; +    } + +    gr->width = w ; +    gr->height = h ; + +    gr->format = bitmap_create_format( depth ) ; + +    gr->pitch = bytesPerRow ; +    gr->widthb = wb ; + +    gr->code = code ; +    gr->name[ 0 ] = '\0'; + +    gr->ncpoints = 0; +    gr->cpoints = NULL ; + +    gr->format->palette = NULL ; + +    gr->blend_table = NULL ; + +    gr->modified = 0; +    gr->info_flags = 0; + +    return gr ; +} + +/* --------------------------------------------------------------------------- */ + +GRAPH * bitmap_clone( GRAPH * map ) +{ +    GRAPH * gr ; +    uint32_t y; + +    gr = bitmap_new( 0, map->width, map->height, map->format->depth ) ; +    if ( gr == NULL ) return NULL; + +    for ( y = 0 ; y < map->height ; y++ ) +        memcpy(( uint8_t* ) gr->data + gr->pitch * y, ( uint8_t* ) map->data + gr->pitch * y, gr->widthb ); + +    if ( map->cpoints ) +    { +        gr->cpoints = malloc( sizeof( CPOINT ) * map->ncpoints ) ; +        memcpy( gr->cpoints, map->cpoints, sizeof( CPOINT ) * map->ncpoints ) ; +        gr->ncpoints = map->ncpoints ; +    } + +    gr->blend_table = map->blend_table; +    gr->info_flags = map->info_flags & ~GI_EXTERNAL_DATA ; +    gr->modified = map->modified ; +    gr->format->palette = map->format->palette ; +    pal_use( map->format->palette ); + +    memcpy( gr->name, map->name, sizeof( map->name ) ) ; + +    return gr ; +} + +/* --------------------------------------------------------------------------- */ + +void bitmap_add_cpoint( GRAPH * map, int x, int y ) +{ +    map->cpoints = ( CPOINT * ) realloc( map->cpoints, ( map->ncpoints + 1 ) * sizeof( CPOINT ) ) ; +    map->cpoints[ map->ncpoints ].x = x ; +    map->cpoints[ map->ncpoints ].y = y ; +    map->ncpoints++; +} + +/* --------------------------------------------------------------------------- */ +/* + *  FUNCTION : bitmap_set_cpoint + * + *  Set a control point in a graphic + * + *  PARAMS : + *      map             Pointer to the bitmap + *      point           Control point index + *      x               New X coordinate or CPOINT_UNDEFINED to unset + *      y               New Y coordinate or CPOINT_UNDEFINED to unset + * + *  RETURN VALUE : + *      None + * + */ + +void bitmap_set_cpoint( GRAPH * map, uint32_t point, int x, int y ) +{ +    uint32_t n; + +    if ( point < 0 ) return ; + +    if ( point == 0 && !map->modified ) map->modified = 1; + +    if ( map->ncpoints <= point ) +    { +        map->cpoints = ( CPOINT * ) realloc( map->cpoints, ( point + 1 ) * sizeof( CPOINT ) ) ; +        for ( n = map->ncpoints; n < point; n++ ) +        { +            map->cpoints[ n ].x = CPOINT_UNDEFINED; +            map->cpoints[ n ].y = CPOINT_UNDEFINED; +        } +        map->ncpoints = point + 1 ; +    } +    map->cpoints[ point ].x = x; +    map->cpoints[ point ].y = y; +} + +/* --------------------------------------------------------------------------- */ + +void bitmap_destroy( GRAPH * map ) +{ +    if ( !map ) return ; + +    if ( map->cpoints ) free( map->cpoints ) ; + +    if ( map->code > 999 ) bit_clr( map_code_bmp, map->code - 1000 ); + +    if ( map->data && !( map->info_flags & GI_EXTERNAL_DATA ) ) free( map->data ) ; + +    if ( map->format ) +    { +        if ( map->format->palette ) pal_destroy( map->format->palette ) ; +        free ( map->format ); +    } + +    free( map ) ; +} + +/* --------------------------------------------------------------------------- */ +/* Análisis */ + +void bitmap_analize( GRAPH * bitmap ) +{ +    uint32_t x, y; +    int color_present = 0, tranparent_present = 0; + +    if ( bitmap->modified > 1 ) bitmap->modified = 1 ; + +    bitmap->info_flags &= ~( GI_CLEAN | GI_NOCOLORKEY ); + +    /* Search for transparent pixels (value 0). +     * If none found, set the flag GI_NOCOLORKEY */ + +    switch ( bitmap->format->depth ) +    { +        case    8: +        { +            uint8_t * ptr = ( uint8_t * ) bitmap->data ; +            int inc = bitmap->pitch - bitmap->widthb ; + +            for ( y = bitmap->height; y--; ptr = ((( uint8_t * ) ptr ) + inc ) ) +            { +                for ( x = bitmap->width; x--; ) { +                    if ( *ptr ) color_present = 1; +                    if ( !*ptr++ ) tranparent_present = 1; +                } +                if ( color_present && tranparent_present ) break; +            } +        } +        break; +        case    16: +        { +            int16_t * ptr = ( int16_t * ) bitmap->data ; +            int inc = bitmap->pitch - bitmap->widthb ; + +            for ( y = bitmap->height; y--; ptr = ( int16_t * )((( uint8_t * ) ptr ) + inc ) ) +            { +                for ( x = bitmap->width; x--; ) { +                    if ( *ptr ) color_present = 1; +                    if ( !*ptr++ ) tranparent_present = 1; +                } +                if ( color_present && tranparent_present ) break; +            } +        } +        break; +        case    32: +        { +            int32_t * ptr = ( int32_t * ) bitmap->data ; +            int inc = bitmap->pitch - bitmap->widthb ; + +            for ( y = bitmap->height; y--; ptr = ( int32_t * )((( uint8_t * ) ptr ) + inc ) ) +            { +                for ( x = bitmap->width; x--; ) { +                    if ( ( *ptr & 0xff000000 ) != 0x00000000 ) color_present = 1; +                    if ( !*ptr ) tranparent_present = 1; +                    ptr++; +                } +                if ( color_present && tranparent_present ) break; +            } +        } +    } + +    if ( color_present && !tranparent_present ) { +        bitmap->info_flags |= GI_NOCOLORKEY ; +    } else +    if ( !color_present && tranparent_present ) { +        bitmap->info_flags |= GI_CLEAN ; +    } +} + +/* --------------------------------------------------------------------------- */ +/* Returns the code of a new system library graph (1000+). Searchs +   for free slots if the program creates too many system maps */ + +int bitmap_next_code() +{ +    int n, nb, lim, ini ; + +    // Si tengo suficientes alocados, retorno el siguiente segun map_code_last +    if ( map_code_last < map_code_allocated ) +    { +        if ( !bit_tst( map_code_bmp, map_code_last ) ) +        { +            bit_set( map_code_bmp, map_code_last ); +            return 1000 + map_code_last++ ; +        } +    } + +    // Ya no tengo mas espacio, entonces busco alguno libre entre ~+32 desde el ultimo fijo y ~-32 del ultimo asignado + +    ini = ( map_code_last < map_code_allocated ) ? ( map_code_last >> 5 ) : 0 ; +    lim = ( map_code_allocated >> 5 ) ; + +    while ( 1 ) +    { +        for ( n = ini; n < lim ; n++ ) +        { +            if ( map_code_bmp[n] != ( uint32_t ) 0xFFFFFFFF ) // Aca hay 1 libre, busco cual es +            { +                for ( nb = 0; nb < 32; nb++ ) +                { +                    if ( !bit_tst( map_code_bmp + n, nb ) ) +                    { +                        map_code_last = ( n << 5 ) + nb ; +                        bit_set( map_code_bmp, map_code_last ); +                        return 1000 + map_code_last++ ; +                    } +                } +            } +        } +        if ( !ini ) break; +        lim = ini; +        ini = 0; +    } + +    map_code_last = map_code_allocated ; + +    // Increment space, no more slots availables +    // 256 new maps available for alloc + +    map_code_allocated += 256 ; +    map_code_bmp = ( uint32_t * ) realloc( map_code_bmp, sizeof( uint32_t ) * ( map_code_allocated >> 5 ) ); + +    memset( &map_code_bmp[( map_code_last >> 5 )], 0, 32 );  /* 256 >> 5 = 8 * sizeof ( uint32_t ) = 8 * 4 = 32 */ + +    // Devuelvo map_code_last e incremento en 1, ya que ahora tengo BLOCK_INCR mas que antes +    bit_set( map_code_bmp, map_code_last ); +    return 1000 + map_code_last++ ; + +} + +/* --------------------------------------------------------------------------- */ + +GRAPH * bitmap_new_syslib( int w, int h, int depth ) +{ +    GRAPH * gr ; + +    if ( !syslib ) return NULL; + +    gr = bitmap_new( 0, w, h, depth ) ; +    if ( !gr ) return NULL; + +    gr->code = bitmap_next_code() ; +    grlib_add_map( 0, gr ) ; + +    return gr ; +} + +/* --------------------------------------------------------------------------- */ | 
