Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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