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