SDL-1.2.14
[sdl_omap.git] / src / video / SDL_surface.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 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 }