2 Simple DirectMedia Layer
3 Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "../SDL_internal.h"
23 #include "SDL_video.h"
24 #include "SDL_sysvideo.h"
26 #include "SDL_RLEaccel_c.h"
27 #include "SDL_pixels_c.h"
28 #include "SDL_yuv_c.h"
31 /* Check to make sure we can safely check multiplication of surface w and pitch and it won't overflow size_t */
32 SDL_COMPILE_TIME_ASSERT(surface_size_assumptions,
33 sizeof(int) == sizeof(Sint32) && sizeof(size_t) >= sizeof(Sint32));
38 * Calculate the pad-aligned scanline width of a surface
41 SDL_CalculatePitch(Uint32 format, int width)
45 /* Surface should be 4-byte aligned for speed */
46 pitch = width * SDL_BYTESPERPIXEL(format);
47 switch (SDL_BITSPERPIXEL(format)) {
49 pitch = (pitch + 7) / 8;
52 pitch = (pitch + 1) / 2;
57 pitch = (pitch + 3) & ~3; /* 4-byte aligning */
62 * Create an empty RGB surface of the appropriate depth using the given
63 * enum SDL_PIXELFORMAT_* format
66 SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
71 /* The flags are no longer used, make the compiler happy */
74 /* Allocate the surface */
75 surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
76 if (surface == NULL) {
81 surface->format = SDL_AllocFormat(format);
82 if (!surface->format) {
83 SDL_FreeSurface(surface);
88 surface->pitch = SDL_CalculatePitch(format, width);
89 SDL_SetClipRect(surface, NULL);
91 if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
92 SDL_Palette *palette =
93 SDL_AllocPalette((1 << surface->format->BitsPerPixel));
95 SDL_FreeSurface(surface);
98 if (palette->ncolors == 2) {
99 /* Create a black and white bitmap palette */
100 palette->colors[0].r = 0xFF;
101 palette->colors[0].g = 0xFF;
102 palette->colors[0].b = 0xFF;
103 palette->colors[1].r = 0x00;
104 palette->colors[1].g = 0x00;
105 palette->colors[1].b = 0x00;
107 SDL_SetSurfacePalette(surface, palette);
108 SDL_FreePalette(palette);
112 if (surface->w && surface->h) {
113 /* Assumptions checked in surface_size_assumptions assert above */
114 Sint64 size = ((Sint64)surface->h * surface->pitch);
115 if (size < 0 || size > SDL_MAX_SINT32) {
117 SDL_FreeSurface(surface);
122 surface->pixels = SDL_malloc((size_t)size);
123 if (!surface->pixels) {
124 SDL_FreeSurface(surface);
128 /* This is important for bitmaps */
129 SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
132 /* Allocate an empty mapping */
133 surface->map = SDL_AllocBlitMap();
135 SDL_FreeSurface(surface);
139 /* By default surface with an alpha mask are set up for blending */
140 if (surface->format->Amask) {
141 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
144 /* The surface is ready to go */
145 surface->refcount = 1;
150 * Create an empty RGB surface of the appropriate depth
153 SDL_CreateRGBSurface(Uint32 flags,
154 int width, int height, int depth,
155 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
159 /* Get the pixel format */
160 format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
161 if (format == SDL_PIXELFORMAT_UNKNOWN) {
162 SDL_SetError("Unknown pixel format");
166 return SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format);
170 * Create an RGB surface from an existing memory buffer
173 SDL_CreateRGBSurfaceFrom(void *pixels,
174 int width, int height, int depth, int pitch,
175 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
178 SDL_Surface *surface;
180 surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
181 if (surface != NULL) {
182 surface->flags |= SDL_PREALLOC;
183 surface->pixels = pixels;
186 surface->pitch = pitch;
187 SDL_SetClipRect(surface, NULL);
193 * Create an RGB surface from an existing memory buffer using the given given
194 * enum SDL_PIXELFORMAT_* format
197 SDL_CreateRGBSurfaceWithFormatFrom(void *pixels,
198 int width, int height, int depth, int pitch,
201 SDL_Surface *surface;
203 surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format);
204 if (surface != NULL) {
205 surface->flags |= SDL_PREALLOC;
206 surface->pixels = pixels;
209 surface->pitch = pitch;
210 SDL_SetClipRect(surface, NULL);
216 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
219 return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
221 if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) {
224 SDL_InvalidateMap(surface->map);
230 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
238 flags = surface->map->info.flags;
240 surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
242 surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
244 if (surface->map->info.flags != flags) {
245 SDL_InvalidateMap(surface->map);
251 SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
256 return SDL_InvalidParamError("surface");
259 if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
260 return SDL_InvalidParamError("key");
263 if (flag & SDL_RLEACCEL) {
264 SDL_SetSurfaceRLE(surface, 1);
267 flags = surface->map->info.flags;
269 surface->map->info.flags |= SDL_COPY_COLORKEY;
270 surface->map->info.colorkey = key;
271 if (surface->format->palette) {
272 surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
273 ++surface->format->palette->version;
274 if (!surface->format->palette->version) {
275 surface->format->palette->version = 1;
279 if (surface->format->palette) {
280 surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_OPAQUE;
281 ++surface->format->palette->version;
282 if (!surface->format->palette->version) {
283 surface->format->palette->version = 1;
286 surface->map->info.flags &= ~SDL_COPY_COLORKEY;
288 if (surface->map->info.flags != flags) {
289 SDL_InvalidateMap(surface->map);
296 SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
299 return SDL_InvalidParamError("surface");
302 if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
303 return SDL_SetError("Surface doesn't have a colorkey");
307 *key = surface->map->info.colorkey;
312 /* This is a fairly slow function to switch from colorkey to alpha */
314 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
322 if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
323 !surface->format->Amask) {
327 SDL_LockSurface(surface);
329 switch (surface->format->BytesPerPixel) {
333 Uint16 ckey = (Uint16) surface->map->info.colorkey;
334 Uint16 mask = (Uint16) (~surface->format->Amask);
336 /* Ignore alpha in colorkey comparison */
338 row = (Uint16 *) surface->pixels;
339 for (y = surface->h; y--;) {
341 for (x = surface->w; x--;) {
342 if ((*spot & mask) == ckey) {
347 row += surface->pitch / 2;
357 Uint32 ckey = surface->map->info.colorkey;
358 Uint32 mask = ~surface->format->Amask;
360 /* Ignore alpha in colorkey comparison */
362 row = (Uint32 *) surface->pixels;
363 for (y = surface->h; y--;) {
365 for (x = surface->w; x--;) {
366 if ((*spot & mask) == ckey) {
371 row += surface->pitch / 4;
377 SDL_UnlockSurface(surface);
379 SDL_SetColorKey(surface, 0, 0);
380 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
384 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
392 surface->map->info.r = r;
393 surface->map->info.g = g;
394 surface->map->info.b = b;
396 flags = surface->map->info.flags;
397 if (r != 0xFF || g != 0xFF || b != 0xFF) {
398 surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
400 surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
402 if (surface->map->info.flags != flags) {
403 SDL_InvalidateMap(surface->map);
410 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
417 *r = surface->map->info.r;
420 *g = surface->map->info.g;
423 *b = surface->map->info.b;
429 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
437 surface->map->info.a = alpha;
439 flags = surface->map->info.flags;
441 surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
443 surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
445 if (surface->map->info.flags != flags) {
446 SDL_InvalidateMap(surface->map);
452 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
459 *alpha = surface->map->info.a;
465 SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
474 flags = surface->map->info.flags;
475 surface->map->info.flags &=
476 ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
478 case SDL_BLENDMODE_NONE:
480 case SDL_BLENDMODE_BLEND:
481 surface->map->info.flags |= SDL_COPY_BLEND;
483 case SDL_BLENDMODE_ADD:
484 surface->map->info.flags |= SDL_COPY_ADD;
486 case SDL_BLENDMODE_MOD:
487 surface->map->info.flags |= SDL_COPY_MOD;
490 status = SDL_Unsupported();
494 if (surface->map->info.flags != flags) {
495 SDL_InvalidateMap(surface->map);
502 SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
512 switch (surface->map->
513 info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD)) {
515 *blendMode = SDL_BLENDMODE_BLEND;
518 *blendMode = SDL_BLENDMODE_ADD;
521 *blendMode = SDL_BLENDMODE_MOD;
524 *blendMode = SDL_BLENDMODE_NONE;
531 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
535 /* Don't do anything if there's no surface to act on */
540 /* Set up the full surface rectangle */
543 full_rect.w = surface->w;
544 full_rect.h = surface->h;
546 /* Set the clipping rectangle */
548 surface->clip_rect = full_rect;
551 return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
555 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
557 if (surface && rect) {
558 *rect = surface->clip_rect;
563 * Set up a blit between two surfaces -- split into three parts:
564 * The upper part, SDL_UpperBlit(), performs clipping and rectangle
565 * verification. The lower part is a pointer to a low level
566 * accelerated blitting function.
568 * These parts are separated out and each used internally by this
569 * library in the optimimum places. They are exported so that if
570 * you know exactly what you are doing, you can optimize your code
571 * by calling the one(s) you need.
574 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
575 SDL_Surface * dst, SDL_Rect * dstrect)
577 /* Check to make sure the blit mapping is valid */
578 if ((src->map->dst != dst) ||
579 (dst->format->palette &&
580 src->map->dst_palette_version != dst->format->palette->version) ||
581 (src->format->palette &&
582 src->map->src_palette_version != src->format->palette->version)) {
583 if (SDL_MapSurface(src, dst) < 0) {
586 /* just here for debugging */
588 /* ("src = 0x%08X src->flags = %08X src->map->info.flags = %08x\ndst = 0x%08X dst->flags = %08X dst->map->info.flags = %08X\nsrc->map->blit = 0x%08x\n", */
589 /* src, dst->flags, src->map->info.flags, dst, dst->flags, */
590 /* dst->map->info.flags, src->map->blit); */
592 return (src->map->blit(src, srcrect, dst, dstrect));
597 SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
598 SDL_Surface * dst, SDL_Rect * dstrect)
601 int srcx, srcy, w, h;
603 /* Make sure the surfaces aren't locked */
605 return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
607 if (src->locked || dst->locked) {
608 return SDL_SetError("Surfaces must not be locked during blit");
611 /* If the destination rectangle is NULL, use the entire dest surface */
612 if (dstrect == NULL) {
613 fulldst.x = fulldst.y = 0;
619 /* clip the source rectangle to the source surface */
630 maxw = src->w - srcx;
641 maxh = src->h - srcy;
651 /* clip the destination rectangle against the clip rectangle */
653 SDL_Rect *clip = &dst->clip_rect;
656 dx = clip->x - dstrect->x;
662 dx = dstrect->x + w - clip->x - clip->w;
666 dy = clip->y - dstrect->y;
672 dy = dstrect->y + h - clip->y - clip->h;
677 /* Switch back to a fast blit if we were previously stretching */
678 if (src->map->info.flags & SDL_COPY_NEAREST) {
679 src->map->info.flags &= ~SDL_COPY_NEAREST;
680 SDL_InvalidateMap(src->map);
683 if (w > 0 && h > 0) {
687 sr.w = dstrect->w = w;
688 sr.h = dstrect->h = h;
689 return SDL_LowerBlit(src, &sr, dst, dstrect);
691 dstrect->w = dstrect->h = 0;
696 SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
697 SDL_Surface * dst, SDL_Rect * dstrect)
699 double src_x0, src_y0, src_x1, src_y1;
700 double dst_x0, dst_y0, dst_x1, dst_y1;
701 SDL_Rect final_src, final_dst;
702 double scaling_w, scaling_h;
706 /* Make sure the surfaces aren't locked */
708 return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
710 if (src->locked || dst->locked) {
711 return SDL_SetError("Surfaces must not be locked during blit");
714 if (NULL == srcrect) {
722 if (NULL == dstrect) {
730 if (dst_w == src_w && dst_h == src_h) {
731 /* No scaling, defer to regular blit */
732 return SDL_BlitSurface(src, srcrect, dst, dstrect);
735 scaling_w = (double)dst_w / src_w;
736 scaling_h = (double)dst_h / src_h;
738 if (NULL == dstrect) {
746 dst_x1 = dst_x0 + dst_w - 1;
747 dst_y1 = dst_y0 + dst_h - 1;
750 if (NULL == srcrect) {
758 src_x1 = src_x0 + src_w - 1;
759 src_y1 = src_y0 + src_h - 1;
761 /* Clip source rectangle to the source surface */
764 dst_x0 -= src_x0 * scaling_w;
768 if (src_x1 >= src->w) {
769 dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
774 dst_y0 -= src_y0 * scaling_h;
778 if (src_y1 >= src->h) {
779 dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
784 /* Clip destination rectangle to the clip rectangle */
786 /* Translate to clip space for easier calculations */
787 dst_x0 -= dst->clip_rect.x;
788 dst_x1 -= dst->clip_rect.x;
789 dst_y0 -= dst->clip_rect.y;
790 dst_y1 -= dst->clip_rect.y;
793 src_x0 -= dst_x0 / scaling_w;
797 if (dst_x1 >= dst->clip_rect.w) {
798 src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
799 dst_x1 = dst->clip_rect.w - 1;
803 src_y0 -= dst_y0 / scaling_h;
807 if (dst_y1 >= dst->clip_rect.h) {
808 src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
809 dst_y1 = dst->clip_rect.h - 1;
812 /* Translate back to surface coordinates */
813 dst_x0 += dst->clip_rect.x;
814 dst_x1 += dst->clip_rect.x;
815 dst_y0 += dst->clip_rect.y;
816 dst_y1 += dst->clip_rect.y;
818 final_src.x = (int)SDL_floor(src_x0 + 0.5);
819 final_src.y = (int)SDL_floor(src_y0 + 0.5);
820 final_src.w = (int)SDL_floor(src_x1 + 1 + 0.5) - (int)SDL_floor(src_x0 + 0.5);
821 final_src.h = (int)SDL_floor(src_y1 + 1 + 0.5) - (int)SDL_floor(src_y0 + 0.5);
823 final_dst.x = (int)SDL_floor(dst_x0 + 0.5);
824 final_dst.y = (int)SDL_floor(dst_y0 + 0.5);
825 final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5);
826 final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5);
834 *dstrect = final_dst;
836 if (final_dst.w == 0 || final_dst.h == 0 ||
837 final_src.w <= 0 || final_src.h <= 0) {
842 return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
846 * This is a semi-private blit function and it performs low-level surface
847 * scaled blitting only.
850 SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
851 SDL_Surface * dst, SDL_Rect * dstrect)
853 static const Uint32 complex_copy_flags = (
854 SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
855 SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD |
859 if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
860 src->map->info.flags |= SDL_COPY_NEAREST;
861 SDL_InvalidateMap(src->map);
864 if ( !(src->map->info.flags & complex_copy_flags) &&
865 src->format->format == dst->format->format &&
866 !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
867 return SDL_SoftStretch( src, srcrect, dst, dstrect );
869 return SDL_LowerBlit( src, srcrect, dst, dstrect );
874 * Lock a surface to directly access the pixels
877 SDL_LockSurface(SDL_Surface * surface)
879 if (!surface->locked) {
880 /* Perform the lock */
881 if (surface->flags & SDL_RLEACCEL) {
882 SDL_UnRLESurface(surface, 1);
883 surface->flags |= SDL_RLEACCEL; /* save accel'd state */
887 /* Increment the surface lock count, for recursive locks */
895 * Unlock a previously locked surface
898 SDL_UnlockSurface(SDL_Surface * surface)
900 /* Only perform an unlock if we are locked */
901 if (!surface->locked || (--surface->locked > 0)) {
905 /* Update RLE encoded surface with new data */
906 if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
907 surface->flags &= ~SDL_RLEACCEL; /* stop lying */
908 SDL_RLESurface(surface);
913 * Creates a new surface identical to the existing surface
916 SDL_DuplicateSurface(SDL_Surface * surface)
918 return SDL_ConvertSurface(surface, surface->format, surface->flags);
922 * Convert a surface into the specified pixel format.
925 SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
928 SDL_Surface *convert;
930 SDL_Color copy_color;
934 SDL_InvalidParamError("surface");
938 SDL_InvalidParamError("format");
942 /* Check for empty destination palette! (results in empty image) */
943 if (format->palette != NULL) {
945 for (i = 0; i < format->palette->ncolors; ++i) {
946 if ((format->palette->colors[i].r != 0xFF) ||
947 (format->palette->colors[i].g != 0xFF) ||
948 (format->palette->colors[i].b != 0xFF))
951 if (i == format->palette->ncolors) {
952 SDL_SetError("Empty destination palette");
957 /* Create a new surface with the desired format */
958 convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
959 format->BitsPerPixel, format->Rmask,
960 format->Gmask, format->Bmask,
962 if (convert == NULL) {
966 /* Copy the palette if any */
967 if (format->palette && convert->format->palette) {
968 SDL_memcpy(convert->format->palette->colors,
969 format->palette->colors,
970 format->palette->ncolors * sizeof(SDL_Color));
971 convert->format->palette->ncolors = format->palette->ncolors;
974 /* Save the original copy flags */
975 copy_flags = surface->map->info.flags;
976 copy_color.r = surface->map->info.r;
977 copy_color.g = surface->map->info.g;
978 copy_color.b = surface->map->info.b;
979 copy_color.a = surface->map->info.a;
980 surface->map->info.r = 0xFF;
981 surface->map->info.g = 0xFF;
982 surface->map->info.b = 0xFF;
983 surface->map->info.a = 0xFF;
984 surface->map->info.flags = 0;
985 SDL_InvalidateMap(surface->map);
987 /* Copy over the image data */
990 bounds.w = surface->w;
991 bounds.h = surface->h;
992 SDL_LowerBlit(surface, &bounds, convert, &bounds);
994 /* Clean up the original surface, and update converted surface */
995 convert->map->info.r = copy_color.r;
996 convert->map->info.g = copy_color.g;
997 convert->map->info.b = copy_color.b;
998 convert->map->info.a = copy_color.a;
999 convert->map->info.flags =
1001 ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
1002 | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
1003 SDL_COPY_RLE_ALPHAKEY));
1004 surface->map->info.r = copy_color.r;
1005 surface->map->info.g = copy_color.g;
1006 surface->map->info.b = copy_color.b;
1007 surface->map->info.a = copy_color.a;
1008 surface->map->info.flags = copy_flags;
1009 SDL_InvalidateMap(surface->map);
1010 if (copy_flags & SDL_COPY_COLORKEY) {
1011 SDL_bool set_colorkey_by_color = SDL_FALSE;
1013 if (surface->format->palette) {
1014 if (format->palette &&
1015 surface->format->palette->ncolors <= format->palette->ncolors &&
1016 (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
1017 surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
1018 /* The palette is identical, just set the same colorkey */
1019 SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
1020 } else if (format->Amask) {
1021 /* The alpha was set in the destination from the palette */
1023 set_colorkey_by_color = SDL_TRUE;
1026 set_colorkey_by_color = SDL_TRUE;
1029 if (set_colorkey_by_color) {
1032 int converted_colorkey = 0;
1034 /* Create a dummy surface to get the colorkey converted */
1035 tmp = SDL_CreateRGBSurface(0, 1, 1,
1036 surface->format->BitsPerPixel, surface->format->Rmask,
1037 surface->format->Gmask, surface->format->Bmask,
1038 surface->format->Amask);
1040 /* Share the palette, if any */
1041 if (surface->format->palette) {
1042 SDL_SetSurfacePalette(tmp, surface->format->palette);
1045 SDL_FillRect(tmp, NULL, surface->map->info.colorkey);
1047 tmp->map->info.flags &= ~SDL_COPY_COLORKEY;
1049 /* Convertion of the colorkey */
1050 tmp2 = SDL_ConvertSurface(tmp, format, 0);
1052 /* Get the converted colorkey */
1053 SDL_memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel);
1055 SDL_FreeSurface(tmp);
1056 SDL_FreeSurface(tmp2);
1058 /* Set the converted colorkey on the new surface */
1059 SDL_SetColorKey(convert, 1, converted_colorkey);
1061 /* This is needed when converting for 3D texture upload */
1062 SDL_ConvertColorkeyToAlpha(convert);
1065 SDL_SetClipRect(convert, &surface->clip_rect);
1067 /* Enable alpha blending by default if the new surface has an
1068 * alpha channel or alpha modulation */
1069 if ((surface->format->Amask && format->Amask) ||
1070 (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
1071 SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
1073 if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
1074 SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
1077 /* We're ready to go! */
1082 SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
1085 SDL_PixelFormat *fmt;
1086 SDL_Surface *convert = NULL;
1088 fmt = SDL_AllocFormat(pixel_format);
1090 convert = SDL_ConvertSurface(surface, fmt, flags);
1091 SDL_FreeFormat(fmt);
1097 * Create a surface on the stack for quick blit operations
1099 static SDL_INLINE SDL_bool
1100 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
1101 void * pixels, int pitch, SDL_Surface * surface,
1102 SDL_PixelFormat * format, SDL_BlitMap * blitmap)
1104 if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
1105 SDL_SetError("Indexed pixel formats not supported");
1108 if (SDL_InitFormat(format, pixel_format) < 0) {
1113 surface->flags = SDL_PREALLOC;
1114 surface->format = format;
1115 surface->pixels = pixels;
1117 surface->h = height;
1118 surface->pitch = pitch;
1119 /* We don't actually need to set up the clip rect for our purposes */
1120 /* SDL_SetClipRect(surface, NULL); */
1122 /* Allocate an empty mapping */
1124 blitmap->info.r = 0xFF;
1125 blitmap->info.g = 0xFF;
1126 blitmap->info.b = 0xFF;
1127 blitmap->info.a = 0xFF;
1128 surface->map = blitmap;
1130 /* The surface is ready to go */
1131 surface->refcount = 1;
1136 * Copy a block of pixels of one format to another format
1138 int SDL_ConvertPixels(int width, int height,
1139 Uint32 src_format, const void * src, int src_pitch,
1140 Uint32 dst_format, void * dst, int dst_pitch)
1142 SDL_Surface src_surface, dst_surface;
1143 SDL_PixelFormat src_fmt, dst_fmt;
1144 SDL_BlitMap src_blitmap, dst_blitmap;
1146 void *nonconst_src = (void *) src;
1148 /* Check to make sure we are blitting somewhere, so we don't crash */
1150 return SDL_InvalidParamError("dst");
1153 return SDL_InvalidParamError("dst_pitch");
1156 if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1157 return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1158 } else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
1159 return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1160 } else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1161 return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1164 /* Fast path for same format copy */
1165 if (src_format == dst_format) {
1167 const int bpp = SDL_BYTESPERPIXEL(src_format);
1169 for (i = height; i--;) {
1170 SDL_memcpy(dst, src, width);
1171 src = (const Uint8*)src + src_pitch;
1172 dst = (Uint8*)dst + dst_pitch;
1177 if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
1179 &src_surface, &src_fmt, &src_blitmap)) {
1182 if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
1183 &dst_surface, &dst_fmt, &dst_blitmap)) {
1187 /* Set up the rect and go! */
1192 return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
1196 * Free a surface created by the above function.
1199 SDL_FreeSurface(SDL_Surface * surface)
1201 if (surface == NULL) {
1204 if (surface->flags & SDL_DONTFREE) {
1207 SDL_InvalidateMap(surface->map);
1209 if (--surface->refcount > 0) {
1212 while (surface->locked > 0) {
1213 SDL_UnlockSurface(surface);
1215 if (surface->flags & SDL_RLEACCEL) {
1216 SDL_UnRLESurface(surface, 0);
1218 if (surface->format) {
1219 SDL_SetSurfacePalette(surface, NULL);
1220 SDL_FreeFormat(surface->format);
1221 surface->format = NULL;
1223 if (!(surface->flags & SDL_PREALLOC)) {
1224 SDL_free(surface->pixels);
1227 SDL_FreeBlitMap(surface->map);
1232 /* vi: set ts=4 sw=4 expandtab: */