src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 01 Aug 2002 23:06:39 +0000
changeset 431 41cadcba32e8
parent 422 b1b9ee41be70
child 441 598b25b9bffe
permissions -rw-r--r--
Fixed SDL_DisplayFormatAlpha() on RGB surfaces with alpha
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  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@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdio.h>
    29 #include <stdlib.h>
    30 #include <string.h>
    31 
    32 #include "SDL_error.h"
    33 #include "SDL_video.h"
    34 #include "SDL_sysvideo.h"
    35 #include "SDL_cursor_c.h"
    36 #include "SDL_blit.h"
    37 #include "SDL_RLEaccel_c.h"
    38 #include "SDL_pixels_c.h"
    39 #include "SDL_memops.h"
    40 #include "SDL_leaks.h"
    41 
    42 /* Public routines */
    43 /*
    44  * Create an empty RGB surface of the appropriate depth
    45  */
    46 SDL_Surface * SDL_CreateRGBSurface (Uint32 flags,
    47 			int width, int height, int depth,
    48 			Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    49 {
    50 	SDL_VideoDevice *video = current_video;
    51 	SDL_VideoDevice *this  = current_video;
    52 	SDL_Surface *screen;
    53 	SDL_Surface *surface;
    54 
    55 	/* Check to see if we desire the surface in video memory */
    56 	if ( video ) {
    57 		screen = SDL_PublicSurface;
    58 	} else {
    59 		screen = NULL;
    60 	}
    61 	if ( screen && ((screen->flags&SDL_HWSURFACE) == SDL_HWSURFACE) ) {
    62 		if ( (flags&(SDL_SRCCOLORKEY|SDL_SRCALPHA)) != 0 ) {
    63 			flags |= SDL_HWSURFACE;
    64 		}
    65 		if ( (flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
    66 			if ( ! current_video->info.blit_hw_CC ) {
    67 				flags &= ~SDL_HWSURFACE;
    68 			}
    69 		}
    70 		if ( (flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
    71 			if ( ! current_video->info.blit_hw_A ) {
    72 				flags &= ~SDL_HWSURFACE;
    73 			}
    74 		}
    75 	} else {
    76 		flags &= ~SDL_HWSURFACE;
    77 	}
    78 
    79 	/* Allocate the surface */
    80 	surface = (SDL_Surface *)malloc(sizeof(*surface));
    81 	if ( surface == NULL ) {
    82 		SDL_OutOfMemory();
    83 		return(NULL);
    84 	}
    85 	surface->flags = SDL_SWSURFACE;
    86 	if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
    87 		depth = screen->format->BitsPerPixel;
    88 		Rmask = screen->format->Rmask;
    89 		Gmask = screen->format->Gmask;
    90 		Bmask = screen->format->Bmask;
    91 		Amask = screen->format->Amask;
    92 	}
    93 	surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
    94 	if ( surface->format == NULL ) {
    95 		free(surface);
    96 		return(NULL);
    97 	}
    98 	if ( Amask ) {
    99 		surface->flags |= SDL_SRCALPHA;
   100 	}
   101 	surface->w = width;
   102 	surface->h = height;
   103 	surface->pitch = SDL_CalculatePitch(surface);
   104 	surface->pixels = NULL;
   105 	surface->offset = 0;
   106 	surface->hwdata = NULL;
   107 	surface->locked = 0;
   108 	surface->map = NULL;
   109 	surface->format_version = 0;
   110 	SDL_SetClipRect(surface, NULL);
   111 
   112 	/* Get the pixels */
   113 	if ( ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) || 
   114 				(video->AllocHWSurface(this, surface) < 0) ) {
   115 		if ( surface->w && surface->h ) {
   116 			surface->pixels = malloc(surface->h*surface->pitch);
   117 			if ( surface->pixels == NULL ) {
   118 				SDL_FreeSurface(surface);
   119 				SDL_OutOfMemory();
   120 				return(NULL);
   121 			}
   122 			/* This is important for bitmaps */
   123 			memset(surface->pixels, 0, surface->h*surface->pitch);
   124 		}
   125 	}
   126 
   127 	/* Allocate an empty mapping */
   128 	surface->map = SDL_AllocBlitMap();
   129 	if ( surface->map == NULL ) {
   130 		SDL_FreeSurface(surface);
   131 		return(NULL);
   132 	}
   133 
   134 	/* The surface is ready to go */
   135 	surface->refcount = 1;
   136 #ifdef CHECK_LEAKS
   137 	++surfaces_allocated;
   138 #endif
   139 	return(surface);
   140 }
   141 /*
   142  * Create an RGB surface from an existing memory buffer
   143  */
   144 SDL_Surface * SDL_CreateRGBSurfaceFrom (void *pixels,
   145 			int width, int height, int depth, int pitch,
   146 			Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   147 {
   148 	SDL_Surface *surface;
   149 
   150 	surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, depth,
   151 	                               Rmask, Gmask, Bmask, Amask);
   152 	if ( surface != NULL ) {
   153 		surface->flags |= SDL_PREALLOC;
   154 		surface->pixels = pixels;
   155 		surface->w = width;
   156 		surface->h = height;
   157 		surface->pitch = pitch;
   158 		SDL_SetClipRect(surface, NULL);
   159 	}
   160 	return(surface);
   161 }
   162 /*
   163  * Set the color key in a blittable surface
   164  */
   165 int SDL_SetColorKey (SDL_Surface *surface, Uint32 flag, Uint32 key)
   166 {
   167 	/* Sanity check the flag as it gets passed in */
   168 	if ( flag & SDL_SRCCOLORKEY ) {
   169 		if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
   170 			flag = (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
   171 		} else {
   172 			flag = SDL_SRCCOLORKEY;
   173 		}
   174 	} else {
   175 		flag = 0;
   176 	}
   177 
   178 	/* Optimize away operations that don't change anything */
   179 	if ( (flag == (surface->flags & (SDL_SRCCOLORKEY|SDL_RLEACCELOK))) &&
   180 	     (key == surface->format->colorkey) ) {
   181 		return(0);
   182 	}
   183 
   184 	/* UnRLE surfaces before we change the colorkey */
   185 	if ( surface->flags & SDL_RLEACCEL ) {
   186 	        SDL_UnRLESurface(surface, 1);
   187 	}
   188 
   189 	if ( flag ) {
   190 		SDL_VideoDevice *video = current_video;
   191 		SDL_VideoDevice *this  = current_video;
   192 
   193 
   194 		surface->flags |= SDL_SRCCOLORKEY;
   195 		surface->format->colorkey = key;
   196 		if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
   197 			if ( (video->SetHWColorKey == NULL) ||
   198 			     (video->SetHWColorKey(this, surface, key) < 0) ) {
   199 				surface->flags &= ~SDL_HWACCEL;
   200 			}
   201 		}
   202 		if ( flag & SDL_RLEACCELOK ) {
   203 			surface->flags |= SDL_RLEACCELOK;
   204 		} else {
   205 			surface->flags &= ~SDL_RLEACCELOK;
   206 		}
   207 	} else {
   208 		surface->flags &= ~(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
   209 		surface->format->colorkey = 0;
   210 	}
   211 	SDL_InvalidateMap(surface->map);
   212 	return(0);
   213 }
   214 /* This function sets the alpha channel of a surface */
   215 int SDL_SetAlpha (SDL_Surface *surface, Uint32 flag, Uint8 value)
   216 {
   217 	Uint32 oldflags = surface->flags;
   218 	Uint32 oldalpha = surface->format->alpha;
   219 
   220 	/* Sanity check the flag as it gets passed in */
   221 	if ( flag & SDL_SRCALPHA ) {
   222 		if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
   223 			flag = (SDL_SRCALPHA | SDL_RLEACCELOK);
   224 		} else {
   225 			flag = SDL_SRCALPHA;
   226 		}
   227 	} else {
   228 		flag = 0;
   229 	}
   230 
   231 	/* Optimize away operations that don't change anything */
   232 	if ( (flag == (surface->flags & (SDL_SRCALPHA|SDL_RLEACCELOK))) &&
   233 	     (!flag || value == oldalpha) ) {
   234 		return(0);
   235 	}
   236 
   237 	if(!(flag & SDL_RLEACCELOK) && (surface->flags & SDL_RLEACCEL))
   238 		SDL_UnRLESurface(surface, 1);
   239 
   240 	if ( flag ) {
   241 		SDL_VideoDevice *video = current_video;
   242 		SDL_VideoDevice *this  = current_video;
   243 
   244 		surface->flags |= SDL_SRCALPHA;
   245 		surface->format->alpha = value;
   246 		if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
   247 			if ( (video->SetHWAlpha == NULL) ||
   248 			     (video->SetHWAlpha(this, surface, value) < 0) ) {
   249 				surface->flags &= ~SDL_HWACCEL;
   250 			}
   251 		}
   252 		if ( flag & SDL_RLEACCELOK ) {
   253 		        surface->flags |= SDL_RLEACCELOK;
   254 		} else {
   255 		        surface->flags &= ~SDL_RLEACCELOK;
   256 		}
   257 	} else {
   258 		surface->flags &= ~SDL_SRCALPHA;
   259 		surface->format->alpha = SDL_ALPHA_OPAQUE;
   260 	}
   261 	/*
   262 	 * The representation for software surfaces is independent of
   263 	 * per-surface alpha, so no need to invalidate the blit mapping
   264 	 * if just the alpha value was changed. (If either is 255, we still
   265 	 * need to invalidate.)
   266 	 */
   267 	if((surface->flags & SDL_HWACCEL) == SDL_HWACCEL
   268 	   || oldflags != surface->flags
   269 	   || (((oldalpha + 1) ^ (value + 1)) & 0x100))
   270 		SDL_InvalidateMap(surface->map);
   271 	return(0);
   272 }
   273 int SDL_SetAlphaChannel(SDL_Surface *surface, Uint8 value)
   274 {
   275 	int row, col;
   276 	int offset;
   277 	Uint8 *buf;
   278 
   279 	if ( (surface->format->Amask != 0xFF000000) &&
   280 	     (surface->format->Amask != 0x000000FF) ) {
   281 		SDL_SetError("Unsupported surface alpha mask format");
   282 		return -1;
   283 	}
   284 
   285 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   286 	if ( surface->format->Amask == 0xFF000000 ) {
   287 			offset = 3;
   288 	} else {
   289 			offset = 0;
   290 	}
   291 #else
   292 	if ( surface->format->Amask == 0xFF000000 ) {
   293 			offset = 0;
   294 	} else {
   295 			offset = 3;
   296 	}
   297 #endif /* Byte ordering */
   298 
   299 	/* Quickly set the alpha channel of an RGBA or ARGB surface */
   300 	if ( SDL_MUSTLOCK(surface) ) {
   301 		if ( SDL_LockSurface(surface) < 0 ) {
   302 			return -1;
   303 		}
   304 	}
   305 	row = surface->h;
   306 	while (row--) {
   307 		col = surface->w;
   308 		buf = (Uint8 *)surface->pixels + row * surface->pitch + offset;
   309 		while(col--) {
   310 			*buf = value;
   311 			buf += 4;
   312 		}
   313 	}
   314 	if ( SDL_MUSTLOCK(surface) ) {
   315 		SDL_UnlockSurface(surface);
   316 	}
   317 	return 0;
   318 }
   319 
   320 /*
   321  * A function to calculate the intersection of two rectangles:
   322  * return true if the rectangles intersect, false otherwise
   323  */
   324 static __inline__
   325 SDL_bool SDL_IntersectRect(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *intersection)
   326 {
   327 	int Amin, Amax, Bmin, Bmax;
   328 
   329 	/* Horizontal intersection */
   330 	Amin = A->x;
   331 	Amax = Amin + A->w;
   332 	Bmin = B->x;
   333 	Bmax = Bmin + B->w;
   334 	if(Bmin > Amin)
   335 	        Amin = Bmin;
   336 	intersection->x = Amin;
   337 	if(Bmax < Amax)
   338 	        Amax = Bmax;
   339 	intersection->w = Amax - Amin > 0 ? Amax - Amin : 0;
   340 
   341 	/* Vertical intersection */
   342 	Amin = A->y;
   343 	Amax = Amin + A->h;
   344 	Bmin = B->y;
   345 	Bmax = Bmin + B->h;
   346 	if(Bmin > Amin)
   347 	        Amin = Bmin;
   348 	intersection->y = Amin;
   349 	if(Bmax < Amax)
   350 	        Amax = Bmax;
   351 	intersection->h = Amax - Amin > 0 ? Amax - Amin : 0;
   352 
   353 	return (intersection->w && intersection->h);
   354 }
   355 /*
   356  * Set the clipping rectangle for a blittable surface
   357  */
   358 SDL_bool SDL_SetClipRect(SDL_Surface *surface, const SDL_Rect *rect)
   359 {
   360 	SDL_Rect full_rect;
   361 
   362 	/* Don't do anything if there's no surface to act on */
   363 	if ( ! surface ) {
   364 		return SDL_FALSE;
   365 	}
   366 
   367 	/* Set up the full surface rectangle */
   368 	full_rect.x = 0;
   369 	full_rect.y = 0;
   370 	full_rect.w = surface->w;
   371 	full_rect.h = surface->h;
   372 
   373 	/* Set the clipping rectangle */
   374 	if ( ! rect ) {
   375 		surface->clip_rect = full_rect;
   376 		return 1;
   377 	}
   378 	return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   379 }
   380 void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect)
   381 {
   382 	if ( surface && rect ) {
   383 		*rect = surface->clip_rect;
   384 	}
   385 }
   386 /* 
   387  * Set up a blit between two surfaces -- split into three parts:
   388  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   389  * verification.  The lower part is a pointer to a low level
   390  * accelerated blitting function.
   391  *
   392  * These parts are separated out and each used internally by this 
   393  * library in the optimimum places.  They are exported so that if
   394  * you know exactly what you are doing, you can optimize your code
   395  * by calling the one(s) you need.
   396  */
   397 int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect,
   398 				SDL_Surface *dst, SDL_Rect *dstrect)
   399 {
   400 	SDL_blit do_blit;
   401 
   402 	/* Check to make sure the blit mapping is valid */
   403 	if ( (src->map->dst != dst) ||
   404              (src->map->dst->format_version != src->map->format_version) ) {
   405 		if ( SDL_MapSurface(src, dst) < 0 ) {
   406 			return(-1);
   407 		}
   408 	}
   409 
   410 	/* Figure out which blitter to use */
   411 	if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
   412 		do_blit = src->map->hw_blit;
   413 	} else {
   414 		do_blit = src->map->sw_blit;
   415 	}
   416 	return(do_blit(src, srcrect, dst, dstrect));
   417 }
   418 
   419 
   420 int SDL_UpperBlit (SDL_Surface *src, SDL_Rect *srcrect,
   421 		   SDL_Surface *dst, SDL_Rect *dstrect)
   422 {
   423         SDL_Rect fulldst;
   424 	int srcx, srcy, w, h;
   425 
   426 	/* Make sure the surfaces aren't locked */
   427 	if ( ! src || ! dst ) {
   428 		SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   429 		return(-1);
   430 	}
   431 	if ( src->locked || dst->locked ) {
   432 		SDL_SetError("Surfaces must not be locked during blit");
   433 		return(-1);
   434 	}
   435 
   436 	/* If the destination rectangle is NULL, use the entire dest surface */
   437 	if ( dstrect == NULL ) {
   438 	        fulldst.x = fulldst.y = 0;
   439 		dstrect = &fulldst;
   440 	}
   441 
   442 	/* clip the source rectangle to the source surface */
   443 	if(srcrect) {
   444 	        int maxw, maxh;
   445 	
   446 		srcx = srcrect->x;
   447 		w = srcrect->w;
   448 		if(srcx < 0) {
   449 		        w += srcx;
   450 			dstrect->x -= srcx;
   451 			srcx = 0;
   452 		}
   453 		maxw = src->w - srcx;
   454 		if(maxw < w)
   455 			w = maxw;
   456 
   457 		srcy = srcrect->y;
   458 		h = srcrect->h;
   459 		if(srcy < 0) {
   460 		        h += srcy;
   461 			dstrect->y -= srcy;
   462 			srcy = 0;
   463 		}
   464 		maxh = src->h - srcy;
   465 		if(maxh < h)
   466 			h = maxh;
   467 	    
   468 	} else {
   469 	        srcx = srcy = 0;
   470 		w = src->w;
   471 		h = src->h;
   472 	}
   473 
   474 	/* clip the destination rectangle against the clip rectangle */
   475 	{
   476 	        SDL_Rect *clip = &dst->clip_rect;
   477 		int dx, dy;
   478 
   479 		dx = clip->x - dstrect->x;
   480 		if(dx > 0) {
   481 			w -= dx;
   482 			dstrect->x += dx;
   483 			srcx += dx;
   484 		}
   485 		dx = dstrect->x + w - clip->x - clip->w;
   486 		if(dx > 0)
   487 			w -= dx;
   488 
   489 		dy = clip->y - dstrect->y;
   490 		if(dy > 0) {
   491 			h -= dy;
   492 			dstrect->y += dy;
   493 			srcy += dy;
   494 		}
   495 		dy = dstrect->y + h - clip->y - clip->h;
   496 		if(dy > 0)
   497 			h -= dy;
   498 	}
   499 
   500 	if(w > 0 && h > 0) {
   501 	        SDL_Rect sr;
   502 	        sr.x = srcx;
   503 		sr.y = srcy;
   504 		sr.w = dstrect->w = w;
   505 		sr.h = dstrect->h = h;
   506 		return SDL_LowerBlit(src, &sr, dst, dstrect);
   507 	}
   508 	dstrect->w = dstrect->h = 0;
   509 	return 0;
   510 }
   511 
   512 /* 
   513  * This function performs a fast fill of the given rectangle with 'color'
   514  */
   515 int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
   516 {
   517 	SDL_VideoDevice *video = current_video;
   518 	SDL_VideoDevice *this  = current_video;
   519 	int x, y;
   520 	Uint8 *row;
   521 
   522 	/* If 'dstrect' == NULL, then fill the whole surface */
   523 	if ( dstrect ) {
   524 		/* Perform clipping */
   525 		if ( !SDL_IntersectRect(dstrect, &dst->clip_rect, dstrect) ) {
   526 			return(0);
   527 		}
   528 	} else {
   529 		dstrect = &dst->clip_rect;
   530 	}
   531 
   532 	/* Check for hardware acceleration */
   533 	if ( ((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) &&
   534 					video->info.blit_fill ) {
   535 		return(video->FillHWRect(this, dst, dstrect, color));
   536 	}
   537 
   538 	/* Perform software fill */
   539 	if ( SDL_LockSurface(dst) != 0 ) {
   540 		return(-1);
   541 	}
   542 	row = (Uint8 *)dst->pixels+dstrect->y*dst->pitch+
   543 			dstrect->x*dst->format->BytesPerPixel;
   544 	if ( dst->format->palette || (color == 0) ) {
   545 		x = dstrect->w*dst->format->BytesPerPixel;
   546 		if ( !color && !((long)row&3) && !(x&3) && !(dst->pitch&3) ) {
   547 			int n = x >> 2;
   548 			for ( y=dstrect->h; y; --y ) {
   549 				SDL_memset4(row, 0, n);
   550 				row += dst->pitch;
   551 			}
   552 		} else {
   553 #ifdef __powerpc__
   554 			/*
   555 			 * memset() on PPC (both glibc and codewarrior) uses
   556 			 * the dcbz (Data Cache Block Zero) instruction, which
   557 			 * causes an alignment exception if the destination is
   558 			 * uncachable, so only use it on software surfaces
   559 			 */
   560 			if((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
   561 				if(dstrect->w >= 8) {
   562 					/*
   563 					 * 64-bit stores are probably most
   564 					 * efficient to uncached video memory
   565 					 */
   566 					double fill;
   567 					memset(&fill, color, (sizeof fill));
   568 					for(y = dstrect->h; y; y--) {
   569 						Uint8 *d = row;
   570 						unsigned n = x;
   571 						unsigned nn;
   572 						Uint8 c = color;
   573 						double f = fill;
   574 						while((unsigned long)d
   575 						      & (sizeof(double) - 1)) {
   576 							*d++ = c;
   577 							n--;
   578 						}
   579 						nn = n / (sizeof(double) * 4);
   580 						while(nn) {
   581 							((double *)d)[0] = f;
   582 							((double *)d)[1] = f;
   583 							((double *)d)[2] = f;
   584 							((double *)d)[3] = f;
   585 							d += 4*sizeof(double);
   586 							nn--;
   587 						}
   588 						n &= ~(sizeof(double) * 4 - 1);
   589 						nn = n / sizeof(double);
   590 						while(nn) {
   591 							*(double *)d = f;
   592 							d += sizeof(double);
   593 							nn--;
   594 						}
   595 						n &= ~(sizeof(double) - 1);
   596 						while(n) {
   597 							*d++ = c;
   598 							n--;
   599 						}
   600 						row += dst->pitch;
   601 					}
   602 				} else {
   603 					/* narrow boxes */
   604 					for(y = dstrect->h; y; y--) {
   605 						Uint8 *d = row;
   606 						Uint8 c = color;
   607 						int n = x;
   608 						while(n) {
   609 							*d++ = c;
   610 							n--;
   611 						}
   612 						row += dst->pitch;
   613 					}
   614 				}
   615 			} else
   616 #endif /* __powerpc__ */
   617 			{
   618 				for(y = dstrect->h; y; y--) {
   619 					memset(row, color, x);
   620 					row += dst->pitch;
   621 				}
   622 			}
   623 		}
   624 	} else {
   625 		switch (dst->format->BytesPerPixel) {
   626 		    case 2:
   627 			for ( y=dstrect->h; y; --y ) {
   628 				Uint16 *pixels = (Uint16 *)row;
   629 				Uint16 c = color;
   630 				Uint32 cc = (Uint32)c << 16 | c;
   631 				int n = dstrect->w;
   632 				if((unsigned long)pixels & 3) {
   633 					*pixels++ = c;
   634 					n--;
   635 				}
   636 				if(n >> 1)
   637 					SDL_memset4(pixels, cc, n >> 1);
   638 				if(n & 1)
   639 					pixels[n - 1] = c;
   640 				row += dst->pitch;
   641 			}
   642 			break;
   643 
   644 		    case 3:
   645 			if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
   646 				color <<= 8;
   647 			for ( y=dstrect->h; y; --y ) {
   648 				Uint8 *pixels = row;
   649 				for ( x=dstrect->w; x; --x ) {
   650 					memcpy(pixels, &color, 3);
   651 					pixels += 3;
   652 				}
   653 				row += dst->pitch;
   654 			}
   655 			break;
   656 
   657 		    case 4:
   658 			for(y = dstrect->h; y; --y) {
   659 				SDL_memset4(row, color, dstrect->w);
   660 				row += dst->pitch;
   661 			}
   662 			break;
   663 		}
   664 	}
   665 	SDL_UnlockSurface(dst);
   666 
   667 	/* We're done! */
   668 	return(0);
   669 }
   670 
   671 /*
   672  * Lock a surface to directly access the pixels
   673  * -- Do not call this from any blit function, as SDL_DrawCursor() may recurse
   674  *    Instead, use:
   675  *    if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )
   676  *               video->LockHWSurface(video, surface);
   677  */
   678 int SDL_LockSurface (SDL_Surface *surface)
   679 {
   680 	if ( ! surface->locked ) {
   681 		/* Perform the lock */
   682 		if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
   683 			SDL_VideoDevice *video = current_video;
   684 			SDL_VideoDevice *this  = current_video;
   685 			if ( video->LockHWSurface(this, surface) < 0 ) {
   686 				return(-1);
   687 			}
   688 		}
   689 		if ( surface->flags & SDL_RLEACCEL ) {
   690 			SDL_UnRLESurface(surface, 1);
   691 			surface->flags |= SDL_RLEACCEL;	/* save accel'd state */
   692 		}
   693 		/* This needs to be done here in case pixels changes value */
   694 		surface->pixels = (Uint8 *)surface->pixels + surface->offset;
   695 	}
   696 
   697 	/* Increment the surface lock count, for recursive locks */
   698 	++surface->locked;
   699 
   700 	/* Ready to go.. */
   701 	return(0);
   702 }
   703 /*
   704  * Unlock a previously locked surface
   705  * -- Do not call this from any blit function, as SDL_DrawCursor() may recurse
   706  *    Instead, use:
   707  *    if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )
   708  *               video->UnlockHWSurface(video, surface);
   709  */
   710 void SDL_UnlockSurface (SDL_Surface *surface)
   711 {
   712 	/* Only perform an unlock if we are locked */
   713 	if ( ! surface->locked || (--surface->locked > 0) ) {
   714 		return;
   715 	}
   716 
   717 	/* Perform the unlock */
   718 	surface->pixels = (Uint8 *)surface->pixels - surface->offset;
   719 
   720 	/* Unlock hardware or accelerated surfaces */
   721 	if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
   722 		SDL_VideoDevice *video = current_video;
   723 		SDL_VideoDevice *this  = current_video;
   724 		video->UnlockHWSurface(this, surface);
   725 	} else {
   726 		/* Update RLE encoded surface with new data */
   727 		if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
   728 		        surface->flags &= ~SDL_RLEACCEL; /* stop lying */
   729 			SDL_RLESurface(surface);
   730 		}
   731 	}
   732 }
   733 
   734 /* 
   735  * Convert a surface into the specified pixel format.
   736  */
   737 SDL_Surface * SDL_ConvertSurface (SDL_Surface *surface,
   738 					SDL_PixelFormat *format, Uint32 flags)
   739 {
   740 	SDL_Surface *convert;
   741 	Uint32 colorkey = 0;
   742 	Uint8 alpha = 0;
   743 	Uint32 surface_flags;
   744 	SDL_Rect bounds;
   745 
   746 	/* Check for empty destination palette! (results in empty image) */
   747 	if ( format->palette != NULL ) {
   748 		int i;
   749 		for ( i=0; i<format->palette->ncolors; ++i ) {
   750 			if ( (format->palette->colors[i].r != 0) ||
   751 			     (format->palette->colors[i].g != 0) ||
   752 			     (format->palette->colors[i].b != 0) )
   753 				break;
   754 		}
   755 		if ( i == format->palette->ncolors ) {
   756 			SDL_SetError("Empty destination palette");
   757 			return(NULL);
   758 		}
   759 	}
   760 
   761 	/* Only create hw surfaces with alpha channel if hw alpha blits
   762 	   are supported */
   763 	if(format->Amask != 0 && (flags & SDL_HWSURFACE)) {
   764 		const SDL_VideoInfo *vi = SDL_GetVideoInfo();
   765 		if(!vi || !vi->blit_hw_A)
   766 			flags &= ~SDL_HWSURFACE;
   767 	}
   768 
   769 	/* Create a new surface with the desired format */
   770 	convert = SDL_CreateRGBSurface(flags,
   771 				surface->w, surface->h, format->BitsPerPixel,
   772 		format->Rmask, format->Gmask, format->Bmask, format->Amask);
   773 	if ( convert == NULL ) {
   774 		return(NULL);
   775 	}
   776 
   777 	/* Copy the palette if any */
   778 	if ( format->palette && convert->format->palette ) {
   779 		memcpy(convert->format->palette->colors,
   780 				format->palette->colors,
   781 				format->palette->ncolors*sizeof(SDL_Color));
   782 		convert->format->palette->ncolors = format->palette->ncolors;
   783 	}
   784 
   785 	/* Save the original surface color key and alpha */
   786 	surface_flags = surface->flags;
   787 	if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
   788 		/* Convert colourkeyed surfaces to RGBA if requested */
   789 		if((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY
   790 		   && format->Amask) {
   791 			surface_flags &= ~SDL_SRCCOLORKEY;
   792 		} else {
   793 			colorkey = surface->format->colorkey;
   794 			SDL_SetColorKey(surface, 0, 0);
   795 		}
   796 	}
   797 	if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
   798 		/* Copy over the alpha channel to RGBA if requested */
   799 		if ( format->Amask ) {
   800 			surface->flags &= ~SDL_SRCALPHA;
   801 		} else {
   802 			alpha = surface->format->alpha;
   803 			SDL_SetAlpha(surface, 0, 0);
   804 		}
   805 	}
   806 
   807 	/* Copy over the image data */
   808 	bounds.x = 0;
   809 	bounds.y = 0;
   810 	bounds.w = surface->w;
   811 	bounds.h = surface->h;
   812 	SDL_LowerBlit(surface, &bounds, convert, &bounds);
   813 
   814 	/* Clean up the original surface, and update converted surface */
   815 	if ( convert != NULL ) {
   816 		SDL_SetClipRect(convert, &surface->clip_rect);
   817 	}
   818 	if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
   819 		Uint32 cflags = surface_flags&(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
   820 		if ( convert != NULL ) {
   821 			Uint8 keyR, keyG, keyB;
   822 
   823 			SDL_GetRGB(colorkey,surface->format,&keyR,&keyG,&keyB);
   824 			SDL_SetColorKey(convert, cflags|(flags&SDL_RLEACCELOK),
   825 				SDL_MapRGB(convert->format, keyR, keyG, keyB));
   826 		}
   827 		SDL_SetColorKey(surface, cflags, colorkey);
   828 	}
   829 	if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
   830 		Uint32 aflags = surface_flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
   831 		if ( convert != NULL ) {
   832 		        SDL_SetAlpha(convert, aflags|(flags&SDL_RLEACCELOK),
   833 				alpha);
   834 		}
   835 		if ( format->Amask ) {
   836 			surface->flags |= SDL_SRCALPHA;
   837 		} else {
   838 			SDL_SetAlpha(surface, aflags, alpha);
   839 		}
   840 	}
   841 
   842 	/* We're ready to go! */
   843 	return(convert);
   844 }
   845 
   846 /*
   847  * Free a surface created by the above function.
   848  */
   849 void SDL_FreeSurface (SDL_Surface *surface)
   850 {
   851 	/* Free anything that's not NULL, and not the screen surface */
   852 	if ((surface == NULL) ||
   853 	    (current_video &&
   854 	    ((surface == SDL_ShadowSurface)||(surface == SDL_VideoSurface)))) {
   855 		return;
   856 	}
   857 	if ( --surface->refcount > 0 ) {
   858 		return;
   859 	}
   860 	if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
   861 	        SDL_UnRLESurface(surface, 0);
   862 	}
   863 	if ( surface->format ) {
   864 		SDL_FreeFormat(surface->format);
   865 		surface->format = NULL;
   866 	}
   867 	if ( surface->map != NULL ) {
   868 		SDL_FreeBlitMap(surface->map);
   869 		surface->map = NULL;
   870 	}
   871 	if ( surface->hwdata ) {
   872 		SDL_VideoDevice *video = current_video;
   873 		SDL_VideoDevice *this  = current_video;
   874 		video->FreeHWSurface(this, surface);
   875 	}
   876 	if ( surface->pixels &&
   877 	     ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC) ) {
   878 		free(surface->pixels);
   879 	}
   880 	free(surface);
   881 #ifdef CHECK_LEAKS
   882 	--surfaces_allocated;
   883 #endif
   884 }