aboutsummaryrefslogtreecommitdiff
path: root/modules/libgrbase/g_bitmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/libgrbase/g_bitmap.c')
-rw-r--r--modules/libgrbase/g_bitmap.c463
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 ;
+}
+
+/* --------------------------------------------------------------------------- */