add OMAP layer handling
[sdl_omap.git] / src / video / SDL_surface.c
CommitLineData
e14743d1 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 */
37SDL_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 */
154SDL_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 */
175int 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 */
225int 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}
283int 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 */
334static __inline__
335SDL_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 */
368SDL_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}
390void 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 */
407int 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
444int 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
536static 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
543static 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 */
553int 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 */
736int 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 */
764void 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 */
791SDL_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 */
903void 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}