2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 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 if (SDL_ISPIXELFORMAT_FOURCC(format) || SDL_BITSPERPIXEL(format) >= 8) {
46 pitch = ((Sint64)width * SDL_BYTESPERPIXEL(format));
48 pitch = (((Sint64)width * SDL_BITSPERPIXEL(format)) + 7) / 8;
50 pitch = (pitch + 3) & ~3; /* 4-byte aligning for speed */
55 * Create an empty RGB surface of the appropriate depth using the given
56 * enum SDL_PIXELFORMAT_* format
59 SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
65 /* The flags are no longer used, make the compiler happy */
68 pitch = SDL_CalculatePitch(format, width);
69 if (pitch < 0 || pitch > SDL_MAX_SINT32) {
75 /* Allocate the surface */
76 surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
77 if (surface == NULL) {
82 surface->format = SDL_AllocFormat(format);
83 if (!surface->format) {
84 SDL_FreeSurface(surface);
89 surface->pitch = (int)pitch;
90 SDL_SetClipRect(surface, NULL);
92 if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
93 SDL_Palette *palette =
94 SDL_AllocPalette((1 << surface->format->BitsPerPixel));
96 SDL_FreeSurface(surface);
99 if (palette->ncolors == 2) {
100 /* Create a black and white bitmap palette */
101 palette->colors[0].r = 0xFF;
102 palette->colors[0].g = 0xFF;
103 palette->colors[0].b = 0xFF;
104 palette->colors[1].r = 0x00;
105 palette->colors[1].g = 0x00;
106 palette->colors[1].b = 0x00;
108 SDL_SetSurfacePalette(surface, palette);
109 SDL_FreePalette(palette);
113 if (surface->w && surface->h) {
114 /* Assumptions checked in surface_size_assumptions assert above */
115 Sint64 size = ((Sint64)surface->h * surface->pitch);
116 if (size < 0 || size > SDL_MAX_SINT32) {
118 SDL_FreeSurface(surface);
123 surface->pixels = SDL_SIMDAlloc((size_t)size);
124 if (!surface->pixels) {
125 SDL_FreeSurface(surface);
129 surface->flags |= SDL_SIMD_ALIGNED;
130 /* This is important for bitmaps */
131 SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
134 /* Allocate an empty mapping */
135 surface->map = SDL_AllocBlitMap();
137 SDL_FreeSurface(surface);
141 /* By default surface with an alpha mask are set up for blending */
142 if (surface->format->Amask) {
143 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
146 /* The surface is ready to go */
147 surface->refcount = 1;
152 * Create an empty RGB surface of the appropriate depth
155 SDL_CreateRGBSurface(Uint32 flags,
156 int width, int height, int depth,
157 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
161 /* Get the pixel format */
162 format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
163 if (format == SDL_PIXELFORMAT_UNKNOWN) {
164 SDL_SetError("Unknown pixel format");
168 return SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format);
172 * Create an RGB surface from an existing memory buffer
175 SDL_CreateRGBSurfaceFrom(void *pixels,
176 int width, int height, int depth, int pitch,
177 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
180 SDL_Surface *surface;
182 surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
183 if (surface != NULL) {
184 surface->flags |= SDL_PREALLOC;
185 surface->pixels = pixels;
188 surface->pitch = pitch;
189 SDL_SetClipRect(surface, NULL);
195 * Create an RGB surface from an existing memory buffer using the given given
196 * enum SDL_PIXELFORMAT_* format
199 SDL_CreateRGBSurfaceWithFormatFrom(void *pixels,
200 int width, int height, int depth, int pitch,
203 SDL_Surface *surface;
205 surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format);
206 if (surface != NULL) {
207 surface->flags |= SDL_PREALLOC;
208 surface->pixels = pixels;
211 surface->pitch = pitch;
212 SDL_SetClipRect(surface, NULL);
218 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
221 return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
223 if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) {
226 SDL_InvalidateMap(surface->map);
232 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
240 flags = surface->map->info.flags;
242 surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
244 surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
246 if (surface->map->info.flags != flags) {
247 SDL_InvalidateMap(surface->map);
253 SDL_HasSurfaceRLE(SDL_Surface * surface)
259 if (!(surface->map->info.flags & SDL_COPY_RLE_DESIRED)) {
267 SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
272 return SDL_InvalidParamError("surface");
275 if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
276 return SDL_InvalidParamError("key");
279 if (flag & SDL_RLEACCEL) {
280 SDL_SetSurfaceRLE(surface, 1);
283 flags = surface->map->info.flags;
285 surface->map->info.flags |= SDL_COPY_COLORKEY;
286 surface->map->info.colorkey = key;
288 surface->map->info.flags &= ~SDL_COPY_COLORKEY;
290 if (surface->map->info.flags != flags) {
291 SDL_InvalidateMap(surface->map);
298 SDL_HasColorKey(SDL_Surface * surface)
304 if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
312 SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
315 return SDL_InvalidParamError("surface");
318 if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
319 return SDL_SetError("Surface doesn't have a colorkey");
323 *key = surface->map->info.colorkey;
328 /* This is a fairly slow function to switch from colorkey to alpha */
330 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface, SDL_bool ignore_alpha)
338 if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
339 !surface->format->Amask) {
343 SDL_LockSurface(surface);
345 switch (surface->format->BytesPerPixel) {
349 Uint16 ckey = (Uint16) surface->map->info.colorkey;
350 Uint16 mask = (Uint16) (~surface->format->Amask);
352 /* Ignore, or not, alpha in colorkey comparison */
355 row = (Uint16 *) surface->pixels;
356 for (y = surface->h; y--;) {
358 for (x = surface->w; x--;) {
359 if ((*spot & mask) == ckey) {
364 row += surface->pitch / 2;
367 row = (Uint16 *) surface->pixels;
368 for (y = surface->h; y--;) {
370 for (x = surface->w; x--;) {
376 row += surface->pitch / 2;
387 Uint32 ckey = surface->map->info.colorkey;
388 Uint32 mask = ~surface->format->Amask;
390 /* Ignore, or not, alpha in colorkey comparison */
393 row = (Uint32 *) surface->pixels;
394 for (y = surface->h; y--;) {
396 for (x = surface->w; x--;) {
397 if ((*spot & mask) == ckey) {
402 row += surface->pitch / 4;
405 row = (Uint32 *) surface->pixels;
406 for (y = surface->h; y--;) {
408 for (x = surface->w; x--;) {
414 row += surface->pitch / 4;
421 SDL_UnlockSurface(surface);
423 SDL_SetColorKey(surface, 0, 0);
424 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
428 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
436 surface->map->info.r = r;
437 surface->map->info.g = g;
438 surface->map->info.b = b;
440 flags = surface->map->info.flags;
441 if (r != 0xFF || g != 0xFF || b != 0xFF) {
442 surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
444 surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
446 if (surface->map->info.flags != flags) {
447 SDL_InvalidateMap(surface->map);
454 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
461 *r = surface->map->info.r;
464 *g = surface->map->info.g;
467 *b = surface->map->info.b;
473 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
481 surface->map->info.a = alpha;
483 flags = surface->map->info.flags;
485 surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
487 surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
489 if (surface->map->info.flags != flags) {
490 SDL_InvalidateMap(surface->map);
496 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
503 *alpha = surface->map->info.a;
509 SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
518 flags = surface->map->info.flags;
519 surface->map->info.flags &=
520 ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL);
522 case SDL_BLENDMODE_NONE:
524 case SDL_BLENDMODE_BLEND:
525 surface->map->info.flags |= SDL_COPY_BLEND;
527 case SDL_BLENDMODE_ADD:
528 surface->map->info.flags |= SDL_COPY_ADD;
530 case SDL_BLENDMODE_MOD:
531 surface->map->info.flags |= SDL_COPY_MOD;
533 case SDL_BLENDMODE_MUL:
534 surface->map->info.flags |= SDL_COPY_MUL;
537 status = SDL_Unsupported();
541 if (surface->map->info.flags != flags) {
542 SDL_InvalidateMap(surface->map);
549 SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
559 switch (surface->map->
560 info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) {
562 *blendMode = SDL_BLENDMODE_BLEND;
565 *blendMode = SDL_BLENDMODE_ADD;
568 *blendMode = SDL_BLENDMODE_MOD;
571 *blendMode = SDL_BLENDMODE_MUL;
574 *blendMode = SDL_BLENDMODE_NONE;
581 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
585 /* Don't do anything if there's no surface to act on */
590 /* Set up the full surface rectangle */
593 full_rect.w = surface->w;
594 full_rect.h = surface->h;
596 /* Set the clipping rectangle */
598 surface->clip_rect = full_rect;
601 return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
605 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
607 if (surface && rect) {
608 *rect = surface->clip_rect;
613 * Set up a blit between two surfaces -- split into three parts:
614 * The upper part, SDL_UpperBlit(), performs clipping and rectangle
615 * verification. The lower part is a pointer to a low level
616 * accelerated blitting function.
618 * These parts are separated out and each used internally by this
619 * library in the optimimum places. They are exported so that if
620 * you know exactly what you are doing, you can optimize your code
621 * by calling the one(s) you need.
624 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
625 SDL_Surface * dst, SDL_Rect * dstrect)
627 /* Check to make sure the blit mapping is valid */
628 if ((src->map->dst != dst) ||
629 (dst->format->palette &&
630 src->map->dst_palette_version != dst->format->palette->version) ||
631 (src->format->palette &&
632 src->map->src_palette_version != src->format->palette->version)) {
633 if (SDL_MapSurface(src, dst) < 0) {
636 /* just here for debugging */
638 /* ("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", */
639 /* src, dst->flags, src->map->info.flags, dst, dst->flags, */
640 /* dst->map->info.flags, src->map->blit); */
642 return (src->map->blit(src, srcrect, dst, dstrect));
647 SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
648 SDL_Surface * dst, SDL_Rect * dstrect)
651 int srcx, srcy, w, h;
653 /* Make sure the surfaces aren't locked */
655 return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
657 if (src->locked || dst->locked) {
658 return SDL_SetError("Surfaces must not be locked during blit");
661 /* If the destination rectangle is NULL, use the entire dest surface */
662 if (dstrect == NULL) {
663 fulldst.x = fulldst.y = 0;
669 /* clip the source rectangle to the source surface */
680 maxw = src->w - srcx;
691 maxh = src->h - srcy;
701 /* clip the destination rectangle against the clip rectangle */
703 SDL_Rect *clip = &dst->clip_rect;
706 dx = clip->x - dstrect->x;
712 dx = dstrect->x + w - clip->x - clip->w;
716 dy = clip->y - dstrect->y;
722 dy = dstrect->y + h - clip->y - clip->h;
727 /* Switch back to a fast blit if we were previously stretching */
728 if (src->map->info.flags & SDL_COPY_NEAREST) {
729 src->map->info.flags &= ~SDL_COPY_NEAREST;
730 SDL_InvalidateMap(src->map);
733 if (w > 0 && h > 0) {
737 sr.w = dstrect->w = w;
738 sr.h = dstrect->h = h;
739 return SDL_LowerBlit(src, &sr, dst, dstrect);
741 dstrect->w = dstrect->h = 0;
746 SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
747 SDL_Surface * dst, SDL_Rect * dstrect)
749 double src_x0, src_y0, src_x1, src_y1;
750 double dst_x0, dst_y0, dst_x1, dst_y1;
751 SDL_Rect final_src, final_dst;
752 double scaling_w, scaling_h;
756 /* Make sure the surfaces aren't locked */
758 return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
760 if (src->locked || dst->locked) {
761 return SDL_SetError("Surfaces must not be locked during blit");
764 if (NULL == srcrect) {
772 if (NULL == dstrect) {
780 if (dst_w == src_w && dst_h == src_h) {
781 /* No scaling, defer to regular blit */
782 return SDL_BlitSurface(src, srcrect, dst, dstrect);
785 scaling_w = (double)dst_w / src_w;
786 scaling_h = (double)dst_h / src_h;
788 if (NULL == dstrect) {
796 dst_x1 = dst_x0 + dst_w - 1;
797 dst_y1 = dst_y0 + dst_h - 1;
800 if (NULL == srcrect) {
808 src_x1 = src_x0 + src_w - 1;
809 src_y1 = src_y0 + src_h - 1;
811 /* Clip source rectangle to the source surface */
814 dst_x0 -= src_x0 * scaling_w;
818 if (src_x1 >= src->w) {
819 dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
824 dst_y0 -= src_y0 * scaling_h;
828 if (src_y1 >= src->h) {
829 dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
834 /* Clip destination rectangle to the clip rectangle */
836 /* Translate to clip space for easier calculations */
837 dst_x0 -= dst->clip_rect.x;
838 dst_x1 -= dst->clip_rect.x;
839 dst_y0 -= dst->clip_rect.y;
840 dst_y1 -= dst->clip_rect.y;
843 src_x0 -= dst_x0 / scaling_w;
847 if (dst_x1 >= dst->clip_rect.w) {
848 src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
849 dst_x1 = dst->clip_rect.w - 1;
853 src_y0 -= dst_y0 / scaling_h;
857 if (dst_y1 >= dst->clip_rect.h) {
858 src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
859 dst_y1 = dst->clip_rect.h - 1;
862 /* Translate back to surface coordinates */
863 dst_x0 += dst->clip_rect.x;
864 dst_x1 += dst->clip_rect.x;
865 dst_y0 += dst->clip_rect.y;
866 dst_y1 += dst->clip_rect.y;
868 final_src.x = (int)SDL_floor(src_x0 + 0.5);
869 final_src.y = (int)SDL_floor(src_y0 + 0.5);
870 final_src.w = (int)SDL_floor(src_x1 + 1 + 0.5) - (int)SDL_floor(src_x0 + 0.5);
871 final_src.h = (int)SDL_floor(src_y1 + 1 + 0.5) - (int)SDL_floor(src_y0 + 0.5);
873 final_dst.x = (int)SDL_floor(dst_x0 + 0.5);
874 final_dst.y = (int)SDL_floor(dst_y0 + 0.5);
875 final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5);
876 final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5);
884 *dstrect = final_dst;
886 if (final_dst.w == 0 || final_dst.h == 0 ||
887 final_src.w <= 0 || final_src.h <= 0) {
892 return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
896 * This is a semi-private blit function and it performs low-level surface
897 * scaled blitting only.
900 SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
901 SDL_Surface * dst, SDL_Rect * dstrect)
903 static const Uint32 complex_copy_flags = (
904 SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
905 SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL |
909 if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
910 src->map->info.flags |= SDL_COPY_NEAREST;
911 SDL_InvalidateMap(src->map);
914 if ( !(src->map->info.flags & complex_copy_flags) &&
915 src->format->format == dst->format->format &&
916 !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
917 return SDL_SoftStretch( src, srcrect, dst, dstrect );
919 return SDL_LowerBlit( src, srcrect, dst, dstrect );
924 * Lock a surface to directly access the pixels
927 SDL_LockSurface(SDL_Surface * surface)
929 if (!surface->locked) {
931 /* Perform the lock */
932 if (surface->flags & SDL_RLEACCEL) {
933 SDL_UnRLESurface(surface, 1);
934 surface->flags |= SDL_RLEACCEL; /* save accel'd state */
939 /* Increment the surface lock count, for recursive locks */
947 * Unlock a previously locked surface
950 SDL_UnlockSurface(SDL_Surface * surface)
952 /* Only perform an unlock if we are locked */
953 if (!surface->locked || (--surface->locked > 0)) {
958 /* Update RLE encoded surface with new data */
959 if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
960 surface->flags &= ~SDL_RLEACCEL; /* stop lying */
961 SDL_RLESurface(surface);
967 * Creates a new surface identical to the existing surface
970 SDL_DuplicateSurface(SDL_Surface * surface)
972 return SDL_ConvertSurface(surface, surface->format, surface->flags);
976 * Convert a surface into the specified pixel format.
979 SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
982 SDL_Surface *convert;
984 SDL_Color copy_color;
987 SDL_bool palette_ck_transform = SDL_FALSE;
988 int palette_ck_value = 0;
989 SDL_bool palette_has_alpha = SDL_FALSE;
990 Uint8 *palette_saved_alpha = NULL;
993 SDL_InvalidParamError("surface");
997 SDL_InvalidParamError("format");
1001 /* Check for empty destination palette! (results in empty image) */
1002 if (format->palette != NULL) {
1004 for (i = 0; i < format->palette->ncolors; ++i) {
1005 if ((format->palette->colors[i].r != 0xFF) ||
1006 (format->palette->colors[i].g != 0xFF) ||
1007 (format->palette->colors[i].b != 0xFF))
1010 if (i == format->palette->ncolors) {
1011 SDL_SetError("Empty destination palette");
1016 /* Create a new surface with the desired format */
1017 convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
1018 format->BitsPerPixel, format->Rmask,
1019 format->Gmask, format->Bmask,
1021 if (convert == NULL) {
1025 /* Copy the palette if any */
1026 if (format->palette && convert->format->palette) {
1027 SDL_memcpy(convert->format->palette->colors,
1028 format->palette->colors,
1029 format->palette->ncolors * sizeof(SDL_Color));
1030 convert->format->palette->ncolors = format->palette->ncolors;
1033 /* Save the original copy flags */
1034 copy_flags = surface->map->info.flags;
1035 copy_color.r = surface->map->info.r;
1036 copy_color.g = surface->map->info.g;
1037 copy_color.b = surface->map->info.b;
1038 copy_color.a = surface->map->info.a;
1039 surface->map->info.r = 0xFF;
1040 surface->map->info.g = 0xFF;
1041 surface->map->info.b = 0xFF;
1042 surface->map->info.a = 0xFF;
1043 surface->map->info.flags = (copy_flags & (SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY));
1044 SDL_InvalidateMap(surface->map);
1046 /* Copy over the image data */
1049 bounds.w = surface->w;
1050 bounds.h = surface->h;
1052 /* Source surface has a palette with no real alpha (0 or OPAQUE).
1053 * Destination format has alpha.
1054 * -> set alpha channel to be opaque */
1055 if (surface->format->palette && format->Amask) {
1056 SDL_bool set_opaque = SDL_FALSE;
1058 SDL_bool is_opaque, has_alpha_channel;
1059 SDL_DetectPalette(surface->format->palette, &is_opaque, &has_alpha_channel);
1062 if (!has_alpha_channel) {
1063 set_opaque = SDL_TRUE;
1066 palette_has_alpha = SDL_TRUE;
1069 /* Set opaque and backup palette alpha values */
1072 palette_saved_alpha = SDL_stack_alloc(Uint8, surface->format->palette->ncolors);
1073 for (i = 0; i < surface->format->palette->ncolors; i++) {
1074 palette_saved_alpha[i] = surface->format->palette->colors[i].a;
1075 surface->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
1080 /* Transform colorkey to alpha. for cases where source palette has duplicate values, and colorkey is one of them */
1081 if (copy_flags & SDL_COPY_COLORKEY) {
1082 if (surface->format->palette && !format->palette) {
1083 palette_ck_transform = SDL_TRUE;
1084 palette_has_alpha = SDL_TRUE;
1085 palette_ck_value = surface->format->palette->colors[surface->map->info.colorkey].a;
1086 surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
1090 ret = SDL_LowerBlit(surface, &bounds, convert, &bounds);
1092 /* Restore colorkey alpha value */
1093 if (palette_ck_transform) {
1094 surface->format->palette->colors[surface->map->info.colorkey].a = palette_ck_value;
1097 /* Restore palette alpha values */
1098 if (palette_saved_alpha) {
1100 for (i = 0; i < surface->format->palette->ncolors; i++) {
1101 surface->format->palette->colors[i].a = palette_saved_alpha[i];
1103 SDL_stack_free(palette_saved_alpha);
1106 /* Clean up the original surface, and update converted surface */
1107 convert->map->info.r = copy_color.r;
1108 convert->map->info.g = copy_color.g;
1109 convert->map->info.b = copy_color.b;
1110 convert->map->info.a = copy_color.a;
1111 convert->map->info.flags =
1113 ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
1114 | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
1115 SDL_COPY_RLE_ALPHAKEY));
1116 surface->map->info.r = copy_color.r;
1117 surface->map->info.g = copy_color.g;
1118 surface->map->info.b = copy_color.b;
1119 surface->map->info.a = copy_color.a;
1120 surface->map->info.flags = copy_flags;
1121 SDL_InvalidateMap(surface->map);
1123 /* SDL_LowerBlit failed, and so the conversion */
1125 SDL_FreeSurface(convert);
1129 if (copy_flags & SDL_COPY_COLORKEY) {
1130 SDL_bool set_colorkey_by_color = SDL_FALSE;
1131 SDL_bool convert_colorkey = SDL_TRUE;
1133 if (surface->format->palette) {
1134 if (format->palette &&
1135 surface->format->palette->ncolors <= format->palette->ncolors &&
1136 (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
1137 surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
1138 /* The palette is identical, just set the same colorkey */
1139 SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
1140 } else if (!format->palette) {
1141 if (format->Amask) {
1142 /* No need to add the colorkey, transparency is in the alpha channel*/
1144 /* Only set the colorkey information */
1145 set_colorkey_by_color = SDL_TRUE;
1146 convert_colorkey = SDL_FALSE;
1149 set_colorkey_by_color = SDL_TRUE;
1152 set_colorkey_by_color = SDL_TRUE;
1155 if (set_colorkey_by_color) {
1158 int converted_colorkey = 0;
1160 /* Create a dummy surface to get the colorkey converted */
1161 tmp = SDL_CreateRGBSurface(0, 1, 1,
1162 surface->format->BitsPerPixel, surface->format->Rmask,
1163 surface->format->Gmask, surface->format->Bmask,
1164 surface->format->Amask);
1166 /* Share the palette, if any */
1167 if (surface->format->palette) {
1168 SDL_SetSurfacePalette(tmp, surface->format->palette);
1171 SDL_FillRect(tmp, NULL, surface->map->info.colorkey);
1173 tmp->map->info.flags &= ~SDL_COPY_COLORKEY;
1175 /* Convertion of the colorkey */
1176 tmp2 = SDL_ConvertSurface(tmp, format, 0);
1178 /* Get the converted colorkey */
1179 SDL_memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel);
1181 SDL_FreeSurface(tmp);
1182 SDL_FreeSurface(tmp2);
1184 /* Set the converted colorkey on the new surface */
1185 SDL_SetColorKey(convert, 1, converted_colorkey);
1187 /* This is needed when converting for 3D texture upload */
1188 if (convert_colorkey) {
1189 SDL_ConvertColorkeyToAlpha(convert, SDL_TRUE);
1193 SDL_SetClipRect(convert, &surface->clip_rect);
1195 /* Enable alpha blending by default if the new surface has an
1196 * alpha channel or alpha modulation */
1197 if ((surface->format->Amask && format->Amask) ||
1198 (palette_has_alpha && format->Amask) ||
1199 (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
1200 SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
1202 if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
1203 SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
1206 /* We're ready to go! */
1211 SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
1214 SDL_PixelFormat *fmt;
1215 SDL_Surface *convert = NULL;
1217 fmt = SDL_AllocFormat(pixel_format);
1219 convert = SDL_ConvertSurface(surface, fmt, flags);
1220 SDL_FreeFormat(fmt);
1226 * Create a surface on the stack for quick blit operations
1228 static SDL_INLINE SDL_bool
1229 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
1230 void * pixels, int pitch, SDL_Surface * surface,
1231 SDL_PixelFormat * format, SDL_BlitMap * blitmap)
1233 if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
1234 SDL_SetError("Indexed pixel formats not supported");
1237 if (SDL_InitFormat(format, pixel_format) < 0) {
1242 surface->flags = SDL_PREALLOC;
1243 surface->format = format;
1244 surface->pixels = pixels;
1246 surface->h = height;
1247 surface->pitch = pitch;
1248 /* We don't actually need to set up the clip rect for our purposes */
1249 /* SDL_SetClipRect(surface, NULL); */
1251 /* Allocate an empty mapping */
1253 blitmap->info.r = 0xFF;
1254 blitmap->info.g = 0xFF;
1255 blitmap->info.b = 0xFF;
1256 blitmap->info.a = 0xFF;
1257 surface->map = blitmap;
1259 /* The surface is ready to go */
1260 surface->refcount = 1;
1265 * Copy a block of pixels of one format to another format
1267 int SDL_ConvertPixels(int width, int height,
1268 Uint32 src_format, const void * src, int src_pitch,
1269 Uint32 dst_format, void * dst, int dst_pitch)
1271 SDL_Surface src_surface, dst_surface;
1272 SDL_PixelFormat src_fmt, dst_fmt;
1273 SDL_BlitMap src_blitmap, dst_blitmap;
1275 void *nonconst_src = (void *) src;
1278 /* Check to make sure we are blitting somewhere, so we don't crash */
1280 return SDL_InvalidParamError("dst");
1283 return SDL_InvalidParamError("dst_pitch");
1287 if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1288 return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1289 } else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
1290 return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1291 } else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1292 return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1295 if (SDL_ISPIXELFORMAT_FOURCC(src_format) || SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1296 SDL_SetError("SDL not built with YUV support");
1301 /* Fast path for same format copy */
1302 if (src_format == dst_format) {
1304 const int bpp = SDL_BYTESPERPIXEL(src_format);
1306 for (i = height; i--;) {
1307 SDL_memcpy(dst, src, width);
1308 src = (const Uint8*)src + src_pitch;
1309 dst = (Uint8*)dst + dst_pitch;
1314 if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
1316 &src_surface, &src_fmt, &src_blitmap)) {
1319 if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
1320 &dst_surface, &dst_fmt, &dst_blitmap)) {
1324 /* Set up the rect and go! */
1329 ret = SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
1331 /* Free blitmap reference, after blitting between stack'ed surfaces */
1332 SDL_InvalidateMap(src_surface.map);
1338 * Free a surface created by the above function.
1341 SDL_FreeSurface(SDL_Surface * surface)
1343 if (surface == NULL) {
1346 if (surface->flags & SDL_DONTFREE) {
1349 SDL_InvalidateMap(surface->map);
1351 SDL_InvalidateAllBlitMap(surface);
1353 if (--surface->refcount > 0) {
1356 while (surface->locked > 0) {
1357 SDL_UnlockSurface(surface);
1360 if (surface->flags & SDL_RLEACCEL) {
1361 SDL_UnRLESurface(surface, 0);
1364 if (surface->format) {
1365 SDL_SetSurfacePalette(surface, NULL);
1366 SDL_FreeFormat(surface->format);
1367 surface->format = NULL;
1369 if (surface->flags & SDL_PREALLOC) {
1371 } else if (surface->flags & SDL_SIMD_ALIGNED) {
1373 SDL_SIMDFree(surface->pixels);
1376 SDL_free(surface->pixels);
1379 SDL_FreeBlitMap(surface->map);
1384 /* vi: set ts=4 sw=4 expandtab: */