Home | History | Annotate | Download | only in video
      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 (at) 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 }
    942