src/video/SDL_pixels.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 06 Jan 2006 13:20:10 +0000
changeset 1234 73676c1f56ee
parent 1057 e9d23bb80140
child 1312 c9b51268668f
permissions -rw-r--r--
For sanity's sake, removed the '&' when passing copy_row array to asm.
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@769
     3
    Copyright (C) 1997-2004 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@0
     6
    modify it under the terms of the GNU Library General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@0
     8
    version 2 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@0
    13
    Library General Public License for more details.
slouken@0
    14
slouken@0
    15
    You should have received a copy of the GNU Library General Public
slouken@0
    16
    License along with this library; if not, write to the Free
slouken@0
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@0
    22
slouken@0
    23
#ifdef SAVE_RCSID
slouken@0
    24
static char rcsid =
slouken@0
    25
 "@(#) $Id$";
slouken@0
    26
#endif
slouken@0
    27
slouken@0
    28
/* General (mostly internal) pixel/color manipulation routines for SDL */
slouken@0
    29
slouken@0
    30
#include <stdio.h>
slouken@0
    31
#include <stdlib.h>
slouken@0
    32
#include <string.h>
slouken@0
    33
slouken@0
    34
#include "SDL_error.h"
slouken@0
    35
#include "SDL_endian.h"
slouken@0
    36
#include "SDL_video.h"
slouken@0
    37
#include "SDL_sysvideo.h"
slouken@0
    38
#include "SDL_blit.h"
slouken@0
    39
#include "SDL_pixels_c.h"
slouken@0
    40
#include "SDL_RLEaccel_c.h"
slouken@0
    41
slouken@0
    42
/* Helper functions */
slouken@0
    43
/*
slouken@0
    44
 * Allocate a pixel format structure and fill it according to the given info.
slouken@0
    45
 */
slouken@0
    46
SDL_PixelFormat *SDL_AllocFormat(int bpp,
slouken@0
    47
			Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
slouken@0
    48
{
slouken@0
    49
	SDL_PixelFormat *format;
slouken@0
    50
	Uint32 mask;
slouken@0
    51
slouken@0
    52
	/* Allocate an empty pixel format structure */
slouken@0
    53
	format = malloc(sizeof(*format));
slouken@0
    54
	if ( format == NULL ) {
slouken@0
    55
		SDL_OutOfMemory();
slouken@0
    56
		return(NULL);
slouken@0
    57
	}
slouken@0
    58
	memset(format, 0, sizeof(*format));
slouken@0
    59
	format->alpha = SDL_ALPHA_OPAQUE;
slouken@0
    60
slouken@0
    61
	/* Set up the format */
slouken@0
    62
	format->BitsPerPixel = bpp;
slouken@0
    63
	format->BytesPerPixel = (bpp+7)/8;
slouken@1027
    64
	if ( Rmask || Bmask || Gmask ) { /* Packed pixels with custom mask */
slouken@1027
    65
		format->palette = NULL;
slouken@1027
    66
		format->Rshift = 0;
slouken@1027
    67
		format->Rloss = 8;
slouken@1027
    68
		if ( Rmask ) {
slouken@1027
    69
			for ( mask = Rmask; !(mask&0x01); mask >>= 1 )
slouken@1027
    70
				++format->Rshift;
slouken@1027
    71
			for ( ; (mask&0x01); mask >>= 1 )
slouken@1027
    72
				--format->Rloss;
slouken@1027
    73
		}
slouken@1027
    74
		format->Gshift = 0;
slouken@1027
    75
		format->Gloss = 8;
slouken@1027
    76
		if ( Gmask ) {
slouken@1027
    77
			for ( mask = Gmask; !(mask&0x01); mask >>= 1 )
slouken@1027
    78
				++format->Gshift;
slouken@1027
    79
			for ( ; (mask&0x01); mask >>= 1 )
slouken@1027
    80
				--format->Gloss;
slouken@1027
    81
		}
slouken@1027
    82
		format->Bshift = 0;
slouken@1027
    83
		format->Bloss = 8;
slouken@1027
    84
		if ( Bmask ) {
slouken@1027
    85
			for ( mask = Bmask; !(mask&0x01); mask >>= 1 )
slouken@1027
    86
				++format->Bshift;
slouken@1027
    87
			for ( ; (mask&0x01); mask >>= 1 )
slouken@1027
    88
				--format->Bloss;
slouken@1027
    89
		}
slouken@1027
    90
		format->Ashift = 0;
slouken@1027
    91
		format->Aloss = 8;
slouken@1027
    92
		if ( Amask ) {
slouken@1027
    93
			for ( mask = Amask; !(mask&0x01); mask >>= 1 )
slouken@1027
    94
				++format->Ashift;
slouken@1027
    95
			for ( ; (mask&0x01); mask >>= 1 )
slouken@1027
    96
				--format->Aloss;
slouken@1027
    97
		}
slouken@1027
    98
		format->Rmask = Rmask;
slouken@1027
    99
		format->Gmask = Gmask;
slouken@1027
   100
		format->Bmask = Bmask;
slouken@1027
   101
		format->Amask = Amask;
slouken@1027
   102
	} else if ( bpp > 8 ) {		/* Packed pixels with standard mask */
slouken@0
   103
		/* R-G-B */
slouken@0
   104
		if ( bpp > 24 )
slouken@0
   105
			bpp = 24;
slouken@0
   106
		format->Rloss = 8-(bpp/3);
slouken@0
   107
		format->Gloss = 8-(bpp/3)-(bpp%3);
slouken@0
   108
		format->Bloss = 8-(bpp/3);
slouken@0
   109
		format->Rshift = ((bpp/3)+(bpp%3))+(bpp/3);
slouken@0
   110
		format->Gshift = (bpp/3);
slouken@0
   111
		format->Bshift = 0;
slouken@0
   112
		format->Rmask = ((0xFF>>format->Rloss)<<format->Rshift);
slouken@0
   113
		format->Gmask = ((0xFF>>format->Gloss)<<format->Gshift);
slouken@0
   114
		format->Bmask = ((0xFF>>format->Bloss)<<format->Bshift);
slouken@1057
   115
	} else {
slouken@1057
   116
		/* Palettized formats have no mask info */
slouken@1057
   117
		format->Rloss = 8;
slouken@1057
   118
		format->Gloss = 8;
slouken@1057
   119
		format->Bloss = 8;
slouken@1057
   120
		format->Aloss = 8;
slouken@1057
   121
		format->Rshift = 0;
slouken@1057
   122
		format->Gshift = 0;
slouken@1057
   123
		format->Bshift = 0;
slouken@1057
   124
		format->Ashift = 0;
slouken@1057
   125
		format->Rmask = 0;
slouken@1057
   126
		format->Gmask = 0;
slouken@1057
   127
		format->Bmask = 0;
slouken@1057
   128
		format->Amask = 0;
slouken@1057
   129
	}
slouken@1057
   130
	if ( bpp <= 8 ) {			/* Palettized mode */
slouken@1057
   131
		int ncolors = 1<<bpp;
slouken@1057
   132
#ifdef DEBUG_PALETTE
slouken@1057
   133
		fprintf(stderr,"bpp=%d ncolors=%d\n",bpp,ncolors);
slouken@1057
   134
#endif
slouken@1027
   135
		format->palette = (SDL_Palette *)malloc(sizeof(SDL_Palette));
slouken@1027
   136
		if ( format->palette == NULL ) {
slouken@1027
   137
			SDL_FreeFormat(format);
slouken@1027
   138
			SDL_OutOfMemory();
slouken@1027
   139
			return(NULL);
slouken@1027
   140
		}
slouken@1027
   141
		(format->palette)->ncolors = ncolors;
slouken@1027
   142
		(format->palette)->colors = (SDL_Color *)malloc(
slouken@1027
   143
				(format->palette)->ncolors*sizeof(SDL_Color));
slouken@1027
   144
		if ( (format->palette)->colors == NULL ) {
slouken@1027
   145
			SDL_FreeFormat(format);
slouken@1027
   146
			SDL_OutOfMemory();
slouken@1027
   147
			return(NULL);
slouken@1027
   148
		}
slouken@1057
   149
		if ( Rmask || Bmask || Gmask ) {
slouken@1057
   150
			/* create palette according to masks */
slouken@1057
   151
			int i;
slouken@1057
   152
			int Rm=0,Gm=0,Bm=0;
slouken@1057
   153
			int Rw=0,Gw=0,Bw=0;
slouken@1057
   154
#ifdef ENABLE_PALETTE_ALPHA
slouken@1057
   155
			int Am=0,Aw=0;
slouken@1057
   156
#endif
slouken@1057
   157
			if(Rmask)
slouken@1057
   158
			{
slouken@1057
   159
				Rw=8-format->Rloss;
slouken@1057
   160
				for(i=format->Rloss;i>0;i-=Rw)
slouken@1057
   161
					Rm|=1<<i;
slouken@1057
   162
			}
slouken@1057
   163
#ifdef DEBUG_PALETTE
slouken@1057
   164
			fprintf(stderr,"Rw=%d Rm=0x%02X\n",Rw,Rm);
slouken@1057
   165
#endif
slouken@1057
   166
			if(Gmask)
slouken@1057
   167
			{
slouken@1057
   168
				Gw=8-format->Gloss;
slouken@1057
   169
				for(i=format->Gloss;i>0;i-=Gw)
slouken@1057
   170
					Gm|=1<<i;
slouken@1057
   171
			}
slouken@1057
   172
#ifdef DEBUG_PALETTE
slouken@1057
   173
			fprintf(stderr,"Gw=%d Gm=0x%02X\n",Gw,Gm);
slouken@1057
   174
#endif
slouken@1057
   175
			if(Bmask)
slouken@1057
   176
			{
slouken@1057
   177
				Bw=8-format->Bloss;
slouken@1057
   178
				for(i=format->Bloss;i>0;i-=Bw)
slouken@1057
   179
					Bm|=1<<i;
slouken@1057
   180
			}
slouken@1057
   181
#ifdef DEBUG_PALETTE
slouken@1057
   182
			fprintf(stderr,"Bw=%d Bm=0x%02X\n",Bw,Bm);
slouken@1057
   183
#endif
slouken@1057
   184
#ifdef ENABLE_PALETTE_ALPHA
slouken@1057
   185
			if(Amask)
slouken@1057
   186
			{
slouken@1057
   187
				Aw=8-format->Aloss;
slouken@1057
   188
				for(i=format->Aloss;i>0;i-=Aw)
slouken@1057
   189
					Am|=1<<i;
slouken@1057
   190
			}
slouken@1057
   191
# ifdef DEBUG_PALETTE
slouken@1057
   192
			fprintf(stderr,"Aw=%d Am=0x%02X\n",Aw,Am);
slouken@1057
   193
# endif
slouken@1057
   194
#endif
slouken@1057
   195
			for(i=0; i < ncolors; ++i) {
slouken@1057
   196
				int r,g,b;
slouken@1057
   197
				r=(i&Rmask)>>format->Rshift;
slouken@1057
   198
				r=(r<<format->Rloss)|((r*Rm)>>Rw);
slouken@1057
   199
				format->palette->colors[i].r=r;
slouken@1057
   200
slouken@1057
   201
				g=(i&Gmask)>>format->Gshift;
slouken@1057
   202
				g=(g<<format->Gloss)|((g*Gm)>>Gw);
slouken@1057
   203
				format->palette->colors[i].g=g;
slouken@1057
   204
slouken@1057
   205
				b=(i&Bmask)>>format->Bshift;
slouken@1057
   206
				b=(b<<format->Bloss)|((b*Bm)>>Bw);
slouken@1057
   207
				format->palette->colors[i].b=b;
slouken@1057
   208
slouken@1057
   209
#ifdef ENABLE_PALETTE_ALPHA
slouken@1057
   210
				a=(i&Amask)>>format->Ashift;
slouken@1057
   211
				a=(a<<format->Aloss)|((a*Am)>>Aw);
slouken@1057
   212
				format->palette->colors[i].unused=a;
slouken@1057
   213
#else
slouken@1057
   214
				format->palette->colors[i].unused=0;
slouken@1057
   215
#endif
slouken@1057
   216
			}
slouken@1057
   217
		} else if ( ncolors == 2 ) {
slouken@1027
   218
			/* Create a black and white bitmap palette */
slouken@1027
   219
			format->palette->colors[0].r = 0xFF;
slouken@1027
   220
			format->palette->colors[0].g = 0xFF;
slouken@1027
   221
			format->palette->colors[0].b = 0xFF;
slouken@1027
   222
			format->palette->colors[1].r = 0x00;
slouken@1027
   223
			format->palette->colors[1].g = 0x00;
slouken@1027
   224
			format->palette->colors[1].b = 0x00;
slouken@1027
   225
		} else {
slouken@1027
   226
			/* Create an empty palette */
slouken@1027
   227
			memset((format->palette)->colors, 0,
slouken@1027
   228
				(format->palette)->ncolors*sizeof(SDL_Color));
slouken@1027
   229
		}
slouken@0
   230
	}
slouken@0
   231
	return(format);
slouken@0
   232
}
slouken@0
   233
SDL_PixelFormat *SDL_ReallocFormat(SDL_Surface *surface, int bpp,
slouken@0
   234
			Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
slouken@0
   235
{
slouken@0
   236
	if ( surface->format ) {
slouken@0
   237
		SDL_FreeFormat(surface->format);
slouken@0
   238
		SDL_FormatChanged(surface);
slouken@0
   239
	}
slouken@0
   240
	surface->format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
slouken@0
   241
	return surface->format;
slouken@0
   242
}
slouken@0
   243
slouken@0
   244
/*
slouken@0
   245
 * Change any previous mappings from/to the new surface format
slouken@0
   246
 */
slouken@0
   247
void SDL_FormatChanged(SDL_Surface *surface)
slouken@0
   248
{
slouken@845
   249
	static int format_version = 0;
slouken@845
   250
	++format_version;
slouken@845
   251
	if ( format_version < 0 ) { /* It wrapped... */
slouken@845
   252
		format_version = 1;
slouken@845
   253
	}
slouken@845
   254
	surface->format_version = format_version;
slouken@0
   255
	SDL_InvalidateMap(surface->map);
slouken@0
   256
}
slouken@0
   257
/*
slouken@0
   258
 * Free a previously allocated format structure
slouken@0
   259
 */
slouken@0
   260
void SDL_FreeFormat(SDL_PixelFormat *format)
slouken@0
   261
{
slouken@0
   262
	if ( format ) {
slouken@0
   263
		if ( format->palette ) {
slouken@0
   264
			if ( format->palette->colors ) {
slouken@0
   265
				free(format->palette->colors);
slouken@0
   266
			}
slouken@0
   267
			free(format->palette);
slouken@0
   268
		}
slouken@0
   269
		free(format);
slouken@0
   270
	}
slouken@0
   271
}
slouken@0
   272
/*
slouken@0
   273
 * Calculate an 8-bit (3 red, 3 green, 2 blue) dithered palette of colors
slouken@0
   274
 */
slouken@0
   275
void SDL_DitherColors(SDL_Color *colors, int bpp)
slouken@0
   276
{
slouken@0
   277
	int i;
slouken@0
   278
	if(bpp != 8)
slouken@0
   279
		return;		/* only 8bpp supported right now */
slouken@0
   280
slouken@0
   281
	for(i = 0; i < 256; i++) {
slouken@0
   282
		int r, g, b;
slouken@0
   283
		/* map each bit field to the full [0, 255] interval,
slouken@0
   284
		   so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255) */
slouken@0
   285
		r = i & 0xe0;
slouken@0
   286
		r |= r >> 3 | r >> 6;
slouken@0
   287
		colors[i].r = r;
slouken@0
   288
		g = (i << 3) & 0xe0;
slouken@0
   289
		g |= g >> 3 | g >> 6;
slouken@0
   290
		colors[i].g = g;
slouken@0
   291
		b = i & 0x3;
slouken@0
   292
		b |= b << 2;
slouken@0
   293
		b |= b << 4;
slouken@0
   294
		colors[i].b = b;
slouken@0
   295
	}
slouken@0
   296
}
slouken@0
   297
/* 
slouken@0
   298
 * Calculate the pad-aligned scanline width of a surface
slouken@0
   299
 */
slouken@0
   300
Uint16 SDL_CalculatePitch(SDL_Surface *surface)
slouken@0
   301
{
slouken@0
   302
	Uint16 pitch;
slouken@0
   303
slouken@0
   304
	/* Surface should be 4-byte aligned for speed */
slouken@0
   305
	pitch = surface->w*surface->format->BytesPerPixel;
slouken@0
   306
	switch (surface->format->BitsPerPixel) {
slouken@0
   307
		case 1:
slouken@0
   308
			pitch = (pitch+7)/8;
slouken@0
   309
			break;
slouken@0
   310
		case 4:
slouken@0
   311
			pitch = (pitch+1)/2;
slouken@0
   312
			break;
slouken@0
   313
		default:
slouken@0
   314
			break;
slouken@0
   315
	}
slouken@0
   316
	pitch = (pitch + 3) & ~3;	/* 4-byte aligning */
slouken@0
   317
	return(pitch);
slouken@0
   318
}
slouken@0
   319
/*
slouken@0
   320
 * Match an RGB value to a particular palette index
slouken@0
   321
 */
slouken@0
   322
Uint8 SDL_FindColor(SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b)
slouken@0
   323
{
slouken@0
   324
	/* Do colorspace distance matching */
slouken@0
   325
	unsigned int smallest;
slouken@0
   326
	unsigned int distance;
slouken@0
   327
	int rd, gd, bd;
slouken@0
   328
	int i;
slouken@0
   329
	Uint8 pixel=0;
slouken@0
   330
		
slouken@0
   331
	smallest = ~0;
slouken@0
   332
	for ( i=0; i<pal->ncolors; ++i ) {
slouken@0
   333
		rd = pal->colors[i].r - r;
slouken@0
   334
		gd = pal->colors[i].g - g;
slouken@0
   335
		bd = pal->colors[i].b - b;
slouken@0
   336
		distance = (rd*rd)+(gd*gd)+(bd*bd);
slouken@0
   337
		if ( distance < smallest ) {
slouken@0
   338
			pixel = i;
slouken@0
   339
			if ( distance == 0 ) { /* Perfect match! */
slouken@0
   340
				break;
slouken@0
   341
			}
slouken@0
   342
			smallest = distance;
slouken@0
   343
		}
slouken@0
   344
	}
slouken@0
   345
	return(pixel);
slouken@0
   346
}
slouken@0
   347
slouken@0
   348
/* Find the opaque pixel value corresponding to an RGB triple */
slouken@0
   349
Uint32 SDL_MapRGB(SDL_PixelFormat *format, Uint8 r, Uint8 g, Uint8 b)
slouken@0
   350
{
slouken@0
   351
	if ( format->palette == NULL ) {
slouken@0
   352
		return (r >> format->Rloss) << format->Rshift
slouken@0
   353
		       | (g >> format->Gloss) << format->Gshift
slouken@0
   354
		       | (b >> format->Bloss) << format->Bshift
slouken@0
   355
		       | format->Amask;
slouken@0
   356
	} else {
slouken@0
   357
		return SDL_FindColor(format->palette, r, g, b);
slouken@0
   358
	}
slouken@0
   359
}
slouken@0
   360
slouken@0
   361
/* Find the pixel value corresponding to an RGBA quadruple */
slouken@0
   362
Uint32 SDL_MapRGBA(SDL_PixelFormat *format, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
slouken@0
   363
{
slouken@0
   364
	if ( format->palette == NULL ) {
slouken@0
   365
	        return (r >> format->Rloss) << format->Rshift
slouken@0
   366
		    | (g >> format->Gloss) << format->Gshift
slouken@0
   367
		    | (b >> format->Bloss) << format->Bshift
slouken@0
   368
		    | ((a >> format->Aloss) << format->Ashift & format->Amask);
slouken@0
   369
	} else {
slouken@0
   370
		return SDL_FindColor(format->palette, r, g, b);
slouken@0
   371
	}
slouken@0
   372
}
slouken@0
   373
slouken@0
   374
void SDL_GetRGBA(Uint32 pixel, SDL_PixelFormat *fmt,
slouken@0
   375
		 Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
slouken@0
   376
{
slouken@0
   377
	if ( fmt->palette == NULL ) {
slouken@0
   378
	        /*
slouken@0
   379
		 * This makes sure that the result is mapped to the
slouken@0
   380
		 * interval [0..255], and the maximum value for each
slouken@0
   381
		 * component is 255. This is important to make sure
slouken@0
   382
		 * that white is indeed reported as (255, 255, 255),
slouken@0
   383
		 * and that opaque alpha is 255.
slouken@0
   384
		 * This only works for RGB bit fields at least 4 bit
slouken@0
   385
		 * wide, which is almost always the case.
slouken@0
   386
		 */
slouken@628
   387
	        unsigned v;
slouken@628
   388
		v = (pixel & fmt->Rmask) >> fmt->Rshift;
slouken@688
   389
		*r = (v << fmt->Rloss) + (v >> (8 - (fmt->Rloss << 1)));
slouken@628
   390
		v = (pixel & fmt->Gmask) >> fmt->Gshift;
slouken@688
   391
		*g = (v << fmt->Gloss) + (v >> (8 - (fmt->Gloss << 1)));
slouken@628
   392
		v = (pixel & fmt->Bmask) >> fmt->Bshift;
slouken@688
   393
		*b = (v << fmt->Bloss) + (v >> (8 - (fmt->Bloss << 1)));
slouken@0
   394
		if(fmt->Amask) {
slouken@628
   395
		        v = (pixel & fmt->Amask) >> fmt->Ashift;
slouken@688
   396
			*a = (v << fmt->Aloss) + (v >> (8 - (fmt->Aloss << 1)));
slouken@695
   397
		} else {
slouken@0
   398
		        *a = SDL_ALPHA_OPAQUE;
slouken@695
   399
                }
slouken@0
   400
	} else {
slouken@0
   401
		*r = fmt->palette->colors[pixel].r;
slouken@0
   402
		*g = fmt->palette->colors[pixel].g;
slouken@0
   403
		*b = fmt->palette->colors[pixel].b;
slouken@0
   404
		*a = SDL_ALPHA_OPAQUE;
slouken@0
   405
	}
slouken@0
   406
}
slouken@0
   407
slouken@0
   408
void SDL_GetRGB(Uint32 pixel, SDL_PixelFormat *fmt, Uint8 *r,Uint8 *g,Uint8 *b)
slouken@0
   409
{
slouken@0
   410
	if ( fmt->palette == NULL ) {
slouken@0
   411
	        /* the note for SDL_GetRGBA above applies here too */
slouken@628
   412
	        unsigned v;
slouken@628
   413
		v = (pixel & fmt->Rmask) >> fmt->Rshift;
slouken@688
   414
		*r = (v << fmt->Rloss) + (v >> (8 - (fmt->Rloss << 1)));
slouken@628
   415
		v = (pixel & fmt->Gmask) >> fmt->Gshift;
slouken@688
   416
		*g = (v << fmt->Gloss) + (v >> (8 - (fmt->Gloss << 1)));
slouken@628
   417
		v = (pixel & fmt->Bmask) >> fmt->Bshift;
slouken@688
   418
		*b = (v << fmt->Bloss) + (v >> (8 - (fmt->Bloss << 1)));
slouken@0
   419
	} else {
slouken@0
   420
		*r = fmt->palette->colors[pixel].r;
slouken@0
   421
		*g = fmt->palette->colors[pixel].g;
slouken@0
   422
		*b = fmt->palette->colors[pixel].b;
slouken@0
   423
	}
slouken@0
   424
}
slouken@0
   425
slouken@0
   426
/* Apply gamma to a set of colors - this is easy. :) */
slouken@0
   427
void SDL_ApplyGamma(Uint16 *gamma, SDL_Color *colors, SDL_Color *output,
slouken@0
   428
							int ncolors)
slouken@0
   429
{
slouken@0
   430
	int i;
slouken@0
   431
slouken@0
   432
	for ( i=0; i<ncolors; ++i ) {
slouken@0
   433
		output[i].r = gamma[0*256 + colors[i].r] >> 8;
slouken@0
   434
		output[i].g = gamma[1*256 + colors[i].g] >> 8;
slouken@0
   435
		output[i].b = gamma[2*256 + colors[i].b] >> 8;
slouken@0
   436
	}
slouken@0
   437
}
slouken@0
   438
slouken@0
   439
/* Map from Palette to Palette */
slouken@0
   440
static Uint8 *Map1to1(SDL_Palette *src, SDL_Palette *dst, int *identical)
slouken@0
   441
{
slouken@0
   442
	Uint8 *map;
slouken@0
   443
	int i;
slouken@0
   444
slouken@0
   445
	if ( identical ) {
slouken@0
   446
		if ( src->ncolors <= dst->ncolors ) {
slouken@0
   447
			/* If an identical palette, no need to map */
slouken@0
   448
			if ( memcmp(src->colors, dst->colors, src->ncolors*
slouken@0
   449
						sizeof(SDL_Color)) == 0 ) {
slouken@0
   450
				*identical = 1;
slouken@0
   451
				return(NULL);
slouken@0
   452
			}
slouken@0
   453
		}
slouken@0
   454
		*identical = 0;
slouken@0
   455
	}
slouken@0
   456
	map = (Uint8 *)malloc(src->ncolors);
slouken@0
   457
	if ( map == NULL ) {
slouken@0
   458
		SDL_OutOfMemory();
slouken@0
   459
		return(NULL);
slouken@0
   460
	}
slouken@0
   461
	for ( i=0; i<src->ncolors; ++i ) {
slouken@0
   462
		map[i] = SDL_FindColor(dst,
slouken@0
   463
			src->colors[i].r, src->colors[i].g, src->colors[i].b);
slouken@0
   464
	}
slouken@0
   465
	return(map);
slouken@0
   466
}
slouken@0
   467
/* Map from Palette to BitField */
slouken@0
   468
static Uint8 *Map1toN(SDL_Palette *src, SDL_PixelFormat *dst)
slouken@0
   469
{
slouken@0
   470
	Uint8 *map;
slouken@0
   471
	int i;
slouken@0
   472
	int  bpp;
slouken@50
   473
	unsigned alpha;
slouken@0
   474
slouken@0
   475
	bpp = ((dst->BytesPerPixel == 3) ? 4 : dst->BytesPerPixel);
slouken@0
   476
	map = (Uint8 *)malloc(src->ncolors*bpp);
slouken@0
   477
	if ( map == NULL ) {
slouken@0
   478
		SDL_OutOfMemory();
slouken@0
   479
		return(NULL);
slouken@0
   480
	}
slouken@0
   481
slouken@50
   482
	alpha = dst->Amask ? SDL_ALPHA_OPAQUE : 0;
slouken@0
   483
	/* We memory copy to the pixel map so the endianness is preserved */
slouken@0
   484
	for ( i=0; i<src->ncolors; ++i ) {
slouken@0
   485
		ASSEMBLE_RGBA(&map[i*bpp], dst->BytesPerPixel, dst,
slouken@0
   486
			      src->colors[i].r, src->colors[i].g,
slouken@50
   487
			      src->colors[i].b, alpha);
slouken@0
   488
	}
slouken@0
   489
	return(map);
slouken@0
   490
}
slouken@0
   491
/* Map from BitField to Dithered-Palette to Palette */
slouken@0
   492
static Uint8 *MapNto1(SDL_PixelFormat *src, SDL_Palette *dst, int *identical)
slouken@0
   493
{
slouken@0
   494
	/* Generate a 256 color dither palette */
slouken@0
   495
	SDL_Palette dithered;
slouken@0
   496
	SDL_Color colors[256];
slouken@997
   497
	
slouken@997
   498
	/* SDL_DitherColors does not initialize the 'unused' component of colors,
slouken@997
   499
	   but Map1to1 compares it against dst, so we should initialize it. */  
slouken@997
   500
	memset(colors, 0, sizeof(colors));
slouken@0
   501
slouken@0
   502
	dithered.ncolors = 256;
slouken@0
   503
	SDL_DitherColors(colors, 8);
slouken@0
   504
	dithered.colors = colors;
slouken@0
   505
	return(Map1to1(&dithered, dst, identical));
slouken@0
   506
}
slouken@0
   507
slouken@0
   508
SDL_BlitMap *SDL_AllocBlitMap(void)
slouken@0
   509
{
slouken@0
   510
	SDL_BlitMap *map;
slouken@0
   511
slouken@0
   512
	/* Allocate the empty map */
slouken@0
   513
	map = (SDL_BlitMap *)malloc(sizeof(*map));
slouken@0
   514
	if ( map == NULL ) {
slouken@0
   515
		SDL_OutOfMemory();
slouken@0
   516
		return(NULL);
slouken@0
   517
	}
slouken@0
   518
	memset(map, 0, sizeof(*map));
slouken@0
   519
slouken@0
   520
	/* Allocate the software blit data */
slouken@0
   521
	map->sw_data = (struct private_swaccel *)malloc(sizeof(*map->sw_data));
slouken@0
   522
	if ( map->sw_data == NULL ) {
slouken@0
   523
		SDL_FreeBlitMap(map);
slouken@0
   524
		SDL_OutOfMemory();
slouken@0
   525
		return(NULL);
slouken@0
   526
	}
slouken@0
   527
	memset(map->sw_data, 0, sizeof(*map->sw_data));
slouken@0
   528
slouken@0
   529
	/* It's ready to go */
slouken@0
   530
	return(map);
slouken@0
   531
}
slouken@0
   532
void SDL_InvalidateMap(SDL_BlitMap *map)
slouken@0
   533
{
slouken@0
   534
	if ( ! map ) {
slouken@0
   535
		return;
slouken@0
   536
	}
slouken@0
   537
	map->dst = NULL;
slouken@0
   538
	map->format_version = (unsigned int)-1;
slouken@0
   539
	if ( map->table ) {
slouken@0
   540
		free(map->table);
slouken@0
   541
		map->table = NULL;
slouken@0
   542
	}
slouken@0
   543
}
slouken@0
   544
int SDL_MapSurface (SDL_Surface *src, SDL_Surface *dst)
slouken@0
   545
{
slouken@0
   546
	SDL_PixelFormat *srcfmt;
slouken@0
   547
	SDL_PixelFormat *dstfmt;
slouken@0
   548
	SDL_BlitMap *map;
slouken@0
   549
slouken@0
   550
	/* Clear out any previous mapping */
slouken@0
   551
	map = src->map;
slouken@0
   552
	if ( (src->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
slouken@0
   553
		SDL_UnRLESurface(src, 1);
slouken@0
   554
	}
slouken@0
   555
	SDL_InvalidateMap(map);
slouken@0
   556
slouken@0
   557
	/* Figure out what kind of mapping we're doing */
slouken@0
   558
	map->identity = 0;
slouken@0
   559
	srcfmt = src->format;
slouken@0
   560
	dstfmt = dst->format;
slouken@0
   561
	switch (srcfmt->BytesPerPixel) {
slouken@0
   562
	    case 1:
slouken@0
   563
		switch (dstfmt->BytesPerPixel) {
slouken@0
   564
		    case 1:
slouken@0
   565
			/* Palette --> Palette */
slouken@0
   566
			/* If both SDL_HWSURFACE, assume have same palette */
slouken@0
   567
			if ( ((src->flags & SDL_HWSURFACE) == SDL_HWSURFACE) &&
slouken@0
   568
			     ((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) ) {
slouken@0
   569
				map->identity = 1;
slouken@0
   570
			} else {
slouken@0
   571
				map->table = Map1to1(srcfmt->palette,
slouken@0
   572
					dstfmt->palette, &map->identity);
slouken@0
   573
			}
slouken@0
   574
			if ( ! map->identity ) {
slouken@0
   575
				if ( map->table == NULL ) {
slouken@0
   576
					return(-1);
slouken@0
   577
				}
slouken@0
   578
			}
slouken@0
   579
			if (srcfmt->BitsPerPixel!=dstfmt->BitsPerPixel)
slouken@0
   580
				map->identity = 0;
slouken@0
   581
			break;
slouken@0
   582
slouken@0
   583
		    default:
slouken@0
   584
			/* Palette --> BitField */
slouken@0
   585
			map->table = Map1toN(srcfmt->palette, dstfmt);
slouken@0
   586
			if ( map->table == NULL ) {
slouken@0
   587
				return(-1);
slouken@0
   588
			}
slouken@0
   589
			break;
slouken@0
   590
		}
slouken@0
   591
		break;
slouken@0
   592
	default:
slouken@0
   593
		switch (dstfmt->BytesPerPixel) {
slouken@0
   594
		    case 1:
slouken@0
   595
			/* BitField --> Palette */
slouken@0
   596
			map->table = MapNto1(srcfmt,
slouken@0
   597
					dstfmt->palette, &map->identity);
slouken@0
   598
			if ( ! map->identity ) {
slouken@0
   599
				if ( map->table == NULL ) {
slouken@0
   600
					return(-1);
slouken@0
   601
				}
slouken@0
   602
			}
slouken@0
   603
			map->identity = 0;	/* Don't optimize to copy */
slouken@0
   604
			break;
slouken@0
   605
		    default:
slouken@0
   606
			/* BitField --> BitField */
slouken@0
   607
			if ( FORMAT_EQUAL(srcfmt, dstfmt) )
slouken@0
   608
				map->identity = 1;
slouken@0
   609
			break;
slouken@0
   610
		}
slouken@0
   611
		break;
slouken@0
   612
	}
slouken@0
   613
slouken@0
   614
	map->dst = dst;
slouken@0
   615
	map->format_version = dst->format_version;
slouken@0
   616
slouken@0
   617
	/* Choose your blitters wisely */
slouken@0
   618
	return(SDL_CalculateBlit(src));
slouken@0
   619
}
slouken@0
   620
void SDL_FreeBlitMap(SDL_BlitMap *map)
slouken@0
   621
{
slouken@0
   622
	if ( map ) {
slouken@0
   623
		SDL_InvalidateMap(map);
slouken@0
   624
		if ( map->sw_data != NULL ) {
slouken@0
   625
			free(map->sw_data);
slouken@0
   626
		}
slouken@0
   627
		free(map);
slouken@0
   628
	}
slouken@0
   629
}