1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
4
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.
8
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:
12
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.
20*/
21#include "../SDL_internal.h"
22
23#include "SDL_video.h"
24#include "SDL_sysvideo.h"
25#include "SDL_blit.h"
26#include "SDL_RLEaccel_c.h"
27#include "SDL_pixels_c.h"
28#include "SDL_yuv_c.h"
29#include "../render/SDL_sysrender.h"
30
31
32/* Check to make sure we can safely check multiplication of surface w and pitch and it won't overflow size_t */
33SDL_COMPILE_TIME_ASSERT(surface_size_assumptions,
34 sizeof(int) == sizeof(Sint32) && sizeof(size_t) >= sizeof(Sint32));
35
36/* Public routines */
37
38/*
39 * Calculate the pad-aligned scanline width of a surface
40 */
41static Sint64
42SDL_CalculatePitch(Uint32 format, int width)
43{
44 Sint64 pitch;
45
46 if (SDL_ISPIXELFORMAT_FOURCC(format) || SDL_BITSPERPIXEL(format) >= 8) {
47 pitch = ((Sint64)width * SDL_BYTESPERPIXEL(format));
48 } else {
49 pitch = (((Sint64)width * SDL_BITSPERPIXEL(format)) + 7) / 8;
50 }
51 pitch = (pitch + 3) & ~3; /* 4-byte aligning for speed */
52 return pitch;
53}
54
55/*
56 * Create an empty RGB surface of the appropriate depth using the given
57 * enum SDL_PIXELFORMAT_* format
58 */
59SDL_Surface *
60SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
61 Uint32 format)
62{
63 Sint64 pitch;
64 SDL_Surface *surface;
65
66 /* The flags are no longer used, make the compiler happy */
67 (void)flags;
68
69 pitch = SDL_CalculatePitch(format, width);
70 if (pitch < 0 || pitch > SDL_MAX_SINT32) {
71 /* Overflow... */
72 SDL_OutOfMemory();
73 return NULL;
74 }
75
76 /* Allocate the surface */
77 surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
78 if (surface == NULL) {
79 SDL_OutOfMemory();
80 return NULL;
81 }
82
83 surface->format = SDL_AllocFormat(format);
84 if (!surface->format) {
85 SDL_FreeSurface(surface);
86 return NULL;
87 }
88 surface->w = width;
89 surface->h = height;
90 surface->pitch = (int)pitch;
91 SDL_SetClipRect(surface, NULL);
92
93 if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
94 SDL_Palette *palette =
95 SDL_AllocPalette((1 << surface->format->BitsPerPixel));
96 if (!palette) {
97 SDL_FreeSurface(surface);
98 return NULL;
99 }
100 if (palette->ncolors == 2) {
101 /* Create a black and white bitmap palette */
102 palette->colors[0].r = 0xFF;
103 palette->colors[0].g = 0xFF;
104 palette->colors[0].b = 0xFF;
105 palette->colors[1].r = 0x00;
106 palette->colors[1].g = 0x00;
107 palette->colors[1].b = 0x00;
108 }
109 SDL_SetSurfacePalette(surface, palette);
110 SDL_FreePalette(palette);
111 }
112
113 /* Get the pixels */
114 if (surface->w && surface->h) {
115 /* Assumptions checked in surface_size_assumptions assert above */
116 Sint64 size = ((Sint64)surface->h * surface->pitch);
117 if (size < 0 || size > SDL_MAX_SINT32) {
118 /* Overflow... */
119 SDL_FreeSurface(surface);
120 SDL_OutOfMemory();
121 return NULL;
122 }
123
124 surface->pixels = SDL_SIMDAlloc((size_t)size);
125 if (!surface->pixels) {
126 SDL_FreeSurface(surface);
127 SDL_OutOfMemory();
128 return NULL;
129 }
130 surface->flags |= SDL_SIMD_ALIGNED;
131 /* This is important for bitmaps */
132 SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
133 }
134
135 /* Allocate an empty mapping */
136 surface->map = SDL_AllocBlitMap();
137 if (!surface->map) {
138 SDL_FreeSurface(surface);
139 return NULL;
140 }
141
142 /* By default surface with an alpha mask are set up for blending */
143 if (surface->format->Amask) {
144 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
145 }
146
147 /* The surface is ready to go */
148 surface->refcount = 1;
149 return surface;
150}
151
152/*
153 * Create an empty RGB surface of the appropriate depth
154 */
155SDL_Surface *
156SDL_CreateRGBSurface(Uint32 flags,
157 int width, int height, int depth,
158 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
159{
160 Uint32 format;
161
162 /* Get the pixel format */
163 format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
164 if (format == SDL_PIXELFORMAT_UNKNOWN) {
165 SDL_SetError("Unknown pixel format");
166 return NULL;
167 }
168
169 return SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format);
170}
171
172/*
173 * Create an RGB surface from an existing memory buffer
174 */
175SDL_Surface *
176SDL_CreateRGBSurfaceFrom(void *pixels,
177 int width, int height, int depth, int pitch,
178 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
179 Uint32 Amask)
180{
181 SDL_Surface *surface;
182
183 surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
184 if (surface != NULL) {
185 surface->flags |= SDL_PREALLOC;
186 surface->pixels = pixels;
187 surface->w = width;
188 surface->h = height;
189 surface->pitch = pitch;
190 SDL_SetClipRect(surface, NULL);
191 }
192 return surface;
193}
194
195/*
196 * Create an RGB surface from an existing memory buffer using the given given
197 * enum SDL_PIXELFORMAT_* format
198 */
199SDL_Surface *
200SDL_CreateRGBSurfaceWithFormatFrom(void *pixels,
201 int width, int height, int depth, int pitch,
202 Uint32 format)
203{
204 SDL_Surface *surface;
205
206 surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format);
207 if (surface != NULL) {
208 surface->flags |= SDL_PREALLOC;
209 surface->pixels = pixels;
210 surface->w = width;
211 surface->h = height;
212 surface->pitch = pitch;
213 SDL_SetClipRect(surface, NULL);
214 }
215 return surface;
216}
217
218int
219SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
220{
221 if (!surface) {
222 return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
223 }
224 if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) {
225 return -1;
226 }
227 SDL_InvalidateMap(surface->map);
228
229 return 0;
230}
231
232int
233SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
234{
235 int flags;
236
237 if (!surface) {
238 return -1;
239 }
240
241 flags = surface->map->info.flags;
242 if (flag) {
243 surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
244 } else {
245 surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
246 }
247 if (surface->map->info.flags != flags) {
248 SDL_InvalidateMap(surface->map);
249 }
250 return 0;
251}
252
253SDL_bool
254SDL_HasSurfaceRLE(SDL_Surface * surface)
255{
256 if (!surface) {
257 return SDL_FALSE;
258 }
259
260 if (!(surface->map->info.flags & SDL_COPY_RLE_DESIRED)) {
261 return SDL_FALSE;
262 }
263
264 return SDL_TRUE;
265}
266
267int
268SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
269{
270 int flags;
271
272 if (!surface) {
273 return SDL_InvalidParamError("surface");
274 }
275
276 if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
277 return SDL_InvalidParamError("key");
278 }
279
280 if (flag & SDL_RLEACCEL) {
281 SDL_SetSurfaceRLE(surface, 1);
282 }
283
284 flags = surface->map->info.flags;
285 if (flag) {
286 surface->map->info.flags |= SDL_COPY_COLORKEY;
287 surface->map->info.colorkey = key;
288 } else {
289 surface->map->info.flags &= ~SDL_COPY_COLORKEY;
290 }
291 if (surface->map->info.flags != flags) {
292 SDL_InvalidateMap(surface->map);
293 }
294
295 return 0;
296}
297
298SDL_bool
299SDL_HasColorKey(SDL_Surface * surface)
300{
301 if (!surface) {
302 return SDL_FALSE;
303 }
304
305 if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
306 return SDL_FALSE;
307 }
308
309 return SDL_TRUE;
310}
311
312int
313SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
314{
315 if (!surface) {
316 return SDL_InvalidParamError("surface");
317 }
318
319 if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
320 return SDL_SetError("Surface doesn't have a colorkey");
321 }
322
323 if (key) {
324 *key = surface->map->info.colorkey;
325 }
326 return 0;
327}
328
329/* This is a fairly slow function to switch from colorkey to alpha
330 NB: it doesn't handle bpp 1 or 3, because they have no alpha channel */
331static void
332SDL_ConvertColorkeyToAlpha(SDL_Surface * surface, SDL_bool ignore_alpha)
333{
334 int x, y, bpp;
335
336 if (!surface) {
337 return;
338 }
339
340 if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
341 !surface->format->Amask) {
342 return;
343 }
344
345 bpp = surface->format->BytesPerPixel;
346
347 SDL_LockSurface(surface);
348
349 if (bpp == 2) {
350 Uint16 *row, *spot;
351 Uint16 ckey = (Uint16) surface->map->info.colorkey;
352 Uint16 mask = (Uint16) (~surface->format->Amask);
353
354 /* Ignore, or not, alpha in colorkey comparison */
355 if (ignore_alpha) {
356 ckey &= mask;
357 row = (Uint16 *) surface->pixels;
358 for (y = surface->h; y--;) {
359 spot = row;
360 for (x = surface->w; x--;) {
361 if ((*spot & mask) == ckey) {
362 *spot &= mask;
363 }
364 ++spot;
365 }
366 row += surface->pitch / 2;
367 }
368 } else {
369 row = (Uint16 *) surface->pixels;
370 for (y = surface->h; y--;) {
371 spot = row;
372 for (x = surface->w; x--;) {
373 if (*spot == ckey) {
374 *spot &= mask;
375 }
376 ++spot;
377 }
378 row += surface->pitch / 2;
379 }
380 }
381 } else if (bpp == 4) {
382 Uint32 *row, *spot;
383 Uint32 ckey = surface->map->info.colorkey;
384 Uint32 mask = ~surface->format->Amask;
385
386 /* Ignore, or not, alpha in colorkey comparison */
387 if (ignore_alpha) {
388 ckey &= mask;
389 row = (Uint32 *) surface->pixels;
390 for (y = surface->h; y--;) {
391 spot = row;
392 for (x = surface->w; x--;) {
393 if ((*spot & mask) == ckey) {
394 *spot &= mask;
395 }
396 ++spot;
397 }
398 row += surface->pitch / 4;
399 }
400 } else {
401 row = (Uint32 *) surface->pixels;
402 for (y = surface->h; y--;) {
403 spot = row;
404 for (x = surface->w; x--;) {
405 if (*spot == ckey) {
406 *spot &= mask;
407 }
408 ++spot;
409 }
410 row += surface->pitch / 4;
411 }
412 }
413 }
414
415 SDL_UnlockSurface(surface);
416
417 SDL_SetColorKey(surface, 0, 0);
418 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
419}
420
421int
422SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
423{
424 int flags;
425
426 if (!surface) {
427 return -1;
428 }
429
430 surface->map->info.r = r;
431 surface->map->info.g = g;
432 surface->map->info.b = b;
433
434 flags = surface->map->info.flags;
435 if (r != 0xFF || g != 0xFF || b != 0xFF) {
436 surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
437 } else {
438 surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
439 }
440 if (surface->map->info.flags != flags) {
441 SDL_InvalidateMap(surface->map);
442 }
443 return 0;
444}
445
446
447int
448SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
449{
450 if (!surface) {
451 return -1;
452 }
453
454 if (r) {
455 *r = surface->map->info.r;
456 }
457 if (g) {
458 *g = surface->map->info.g;
459 }
460 if (b) {
461 *b = surface->map->info.b;
462 }
463 return 0;
464}
465
466int
467SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
468{
469 int flags;
470
471 if (!surface) {
472 return -1;
473 }
474
475 surface->map->info.a = alpha;
476
477 flags = surface->map->info.flags;
478 if (alpha != 0xFF) {
479 surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
480 } else {
481 surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
482 }
483 if (surface->map->info.flags != flags) {
484 SDL_InvalidateMap(surface->map);
485 }
486 return 0;
487}
488
489int
490SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
491{
492 if (!surface) {
493 return -1;
494 }
495
496 if (alpha) {
497 *alpha = surface->map->info.a;
498 }
499 return 0;
500}
501
502int
503SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
504{
505 int flags, status;
506
507 if (!surface) {
508 return -1;
509 }
510
511 status = 0;
512 flags = surface->map->info.flags;
513 surface->map->info.flags &=
514 ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL);
515 switch (blendMode) {
516 case SDL_BLENDMODE_NONE:
517 break;
518 case SDL_BLENDMODE_BLEND:
519 surface->map->info.flags |= SDL_COPY_BLEND;
520 break;
521 case SDL_BLENDMODE_ADD:
522 surface->map->info.flags |= SDL_COPY_ADD;
523 break;
524 case SDL_BLENDMODE_MOD:
525 surface->map->info.flags |= SDL_COPY_MOD;
526 break;
527 case SDL_BLENDMODE_MUL:
528 surface->map->info.flags |= SDL_COPY_MUL;
529 break;
530 default:
531 status = SDL_Unsupported();
532 break;
533 }
534
535 if (surface->map->info.flags != flags) {
536 SDL_InvalidateMap(surface->map);
537 }
538
539 return status;
540}
541
542int
543SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
544{
545 if (!surface) {
546 return -1;
547 }
548
549 if (!blendMode) {
550 return 0;
551 }
552
553 switch (surface->map->
554 info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) {
555 case SDL_COPY_BLEND:
556 *blendMode = SDL_BLENDMODE_BLEND;
557 break;
558 case SDL_COPY_ADD:
559 *blendMode = SDL_BLENDMODE_ADD;
560 break;
561 case SDL_COPY_MOD:
562 *blendMode = SDL_BLENDMODE_MOD;
563 break;
564 case SDL_COPY_MUL:
565 *blendMode = SDL_BLENDMODE_MUL;
566 break;
567 default:
568 *blendMode = SDL_BLENDMODE_NONE;
569 break;
570 }
571 return 0;
572}
573
574SDL_bool
575SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
576{
577 SDL_Rect full_rect;
578
579 /* Don't do anything if there's no surface to act on */
580 if (!surface) {
581 return SDL_FALSE;
582 }
583
584 /* Set up the full surface rectangle */
585 full_rect.x = 0;
586 full_rect.y = 0;
587 full_rect.w = surface->w;
588 full_rect.h = surface->h;
589
590 /* Set the clipping rectangle */
591 if (!rect) {
592 surface->clip_rect = full_rect;
593 return SDL_TRUE;
594 }
595 return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
596}
597
598void
599SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
600{
601 if (surface && rect) {
602 *rect = surface->clip_rect;
603 }
604}
605
606/*
607 * Set up a blit between two surfaces -- split into three parts:
608 * The upper part, SDL_UpperBlit(), performs clipping and rectangle
609 * verification. The lower part is a pointer to a low level
610 * accelerated blitting function.
611 *
612 * These parts are separated out and each used internally by this
613 * library in the optimimum places. They are exported so that if
614 * you know exactly what you are doing, you can optimize your code
615 * by calling the one(s) you need.
616 */
617int
618SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
619 SDL_Surface * dst, SDL_Rect * dstrect)
620{
621 /* Check to make sure the blit mapping is valid */
622 if ((src->map->dst != dst) ||
623 (dst->format->palette &&
624 src->map->dst_palette_version != dst->format->palette->version) ||
625 (src->format->palette &&
626 src->map->src_palette_version != src->format->palette->version)) {
627 if (SDL_MapSurface(src, dst) < 0) {
628 return (-1);
629 }
630 /* just here for debugging */
631/* printf */
632/* ("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", */
633/* src, dst->flags, src->map->info.flags, dst, dst->flags, */
634/* dst->map->info.flags, src->map->blit); */
635 }
636 return (src->map->blit(src, srcrect, dst, dstrect));
637}
638
639
640int
641SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
642 SDL_Surface * dst, SDL_Rect * dstrect)
643{
644 SDL_Rect fulldst;
645 int srcx, srcy, w, h;
646
647 /* Make sure the surfaces aren't locked */
648 if (!src || !dst) {
649 return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
650 }
651 if (src->locked || dst->locked) {
652 return SDL_SetError("Surfaces must not be locked during blit");
653 }
654
655 /* If the destination rectangle is NULL, use the entire dest surface */
656 if (dstrect == NULL) {
657 fulldst.x = fulldst.y = 0;
658 fulldst.w = dst->w;
659 fulldst.h = dst->h;
660 dstrect = &fulldst;
661 }
662
663 /* clip the source rectangle to the source surface */
664 if (srcrect) {
665 int maxw, maxh;
666
667 srcx = srcrect->x;
668 w = srcrect->w;
669 if (srcx < 0) {
670 w += srcx;
671 dstrect->x -= srcx;
672 srcx = 0;
673 }
674 maxw = src->w - srcx;
675 if (maxw < w)
676 w = maxw;
677
678 srcy = srcrect->y;
679 h = srcrect->h;
680 if (srcy < 0) {
681 h += srcy;
682 dstrect->y -= srcy;
683 srcy = 0;
684 }
685 maxh = src->h - srcy;
686 if (maxh < h)
687 h = maxh;
688
689 } else {
690 srcx = srcy = 0;
691 w = src->w;
692 h = src->h;
693 }
694
695 /* clip the destination rectangle against the clip rectangle */
696 {
697 SDL_Rect *clip = &dst->clip_rect;
698 int dx, dy;
699
700 dx = clip->x - dstrect->x;
701 if (dx > 0) {
702 w -= dx;
703 dstrect->x += dx;
704 srcx += dx;
705 }
706 dx = dstrect->x + w - clip->x - clip->w;
707 if (dx > 0)
708 w -= dx;
709
710 dy = clip->y - dstrect->y;
711 if (dy > 0) {
712 h -= dy;
713 dstrect->y += dy;
714 srcy += dy;
715 }
716 dy = dstrect->y + h - clip->y - clip->h;
717 if (dy > 0)
718 h -= dy;
719 }
720
721 /* Switch back to a fast blit if we were previously stretching */
722 if (src->map->info.flags & SDL_COPY_NEAREST) {
723 src->map->info.flags &= ~SDL_COPY_NEAREST;
724 SDL_InvalidateMap(src->map);
725 }
726
727 if (w > 0 && h > 0) {
728 SDL_Rect sr;
729 sr.x = srcx;
730 sr.y = srcy;
731 sr.w = dstrect->w = w;
732 sr.h = dstrect->h = h;
733 return SDL_LowerBlit(src, &sr, dst, dstrect);
734 }
735 dstrect->w = dstrect->h = 0;
736 return 0;
737}
738
739int
740SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
741 SDL_Surface * dst, SDL_Rect * dstrect)
742{
743 return SDL_PrivateUpperBlitScaled(src, srcrect, dst, dstrect, SDL_ScaleModeNearest);
744}
745
746
747int
748SDL_PrivateUpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
749 SDL_Surface * dst, SDL_Rect * dstrect, SDL_ScaleMode scaleMode)
750{
751 double src_x0, src_y0, src_x1, src_y1;
752 double dst_x0, dst_y0, dst_x1, dst_y1;
753 SDL_Rect final_src, final_dst;
754 double scaling_w, scaling_h;
755 int src_w, src_h;
756 int dst_w, dst_h;
757
758 /* Make sure the surfaces aren't locked */
759 if (!src || !dst) {
760 return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
761 }
762 if (src->locked || dst->locked) {
763 return SDL_SetError("Surfaces must not be locked during blit");
764 }
765
766 if (NULL == srcrect) {
767 src_w = src->w;
768 src_h = src->h;
769 } else {
770 src_w = srcrect->w;
771 src_h = srcrect->h;
772 }
773
774 if (NULL == dstrect) {
775 dst_w = dst->w;
776 dst_h = dst->h;
777 } else {
778 dst_w = dstrect->w;
779 dst_h = dstrect->h;
780 }
781
782 if (dst_w == src_w && dst_h == src_h) {
783 /* No scaling, defer to regular blit */
784 return SDL_BlitSurface(src, srcrect, dst, dstrect);
785 }
786
787 scaling_w = (double)dst_w / src_w;
788 scaling_h = (double)dst_h / src_h;
789
790 if (NULL == dstrect) {
791 dst_x0 = 0;
792 dst_y0 = 0;
793 dst_x1 = dst_w;
794 dst_y1 = dst_h;
795 } else {
796 dst_x0 = dstrect->x;
797 dst_y0 = dstrect->y;
798 dst_x1 = dst_x0 + dst_w;
799 dst_y1 = dst_y0 + dst_h;
800 }
801
802 if (NULL == srcrect) {
803 src_x0 = 0;
804 src_y0 = 0;
805 src_x1 = src_w;
806 src_y1 = src_h;
807 } else {
808 src_x0 = srcrect->x;
809 src_y0 = srcrect->y;
810 src_x1 = src_x0 + src_w;
811 src_y1 = src_y0 + src_h;
812
813 /* Clip source rectangle to the source surface */
814
815 if (src_x0 < 0) {
816 dst_x0 -= src_x0 * scaling_w;
817 src_x0 = 0;
818 }
819
820 if (src_x1 > src->w) {
821 dst_x1 -= (src_x1 - src->w) * scaling_w;
822 src_x1 = src->w;
823 }
824
825 if (src_y0 < 0) {
826 dst_y0 -= src_y0 * scaling_h;
827 src_y0 = 0;
828 }
829
830 if (src_y1 > src->h) {
831 dst_y1 -= (src_y1 - src->h) * scaling_h;
832 src_y1 = src->h;
833 }
834 }
835
836 /* Clip destination rectangle to the clip rectangle */
837
838 /* Translate to clip space for easier calculations */
839 dst_x0 -= dst->clip_rect.x;
840 dst_x1 -= dst->clip_rect.x;
841 dst_y0 -= dst->clip_rect.y;
842 dst_y1 -= dst->clip_rect.y;
843
844 if (dst_x0 < 0) {
845 src_x0 -= dst_x0 / scaling_w;
846 dst_x0 = 0;
847 }
848
849 if (dst_x1 > dst->clip_rect.w) {
850 src_x1 -= (dst_x1 - dst->clip_rect.w) / scaling_w;
851 dst_x1 = dst->clip_rect.w;
852 }
853
854 if (dst_y0 < 0) {
855 src_y0 -= dst_y0 / scaling_h;
856 dst_y0 = 0;
857 }
858
859 if (dst_y1 > dst->clip_rect.h) {
860 src_y1 -= (dst_y1 - dst->clip_rect.h) / scaling_h;
861 dst_y1 = dst->clip_rect.h;
862 }
863
864 /* Translate back to surface coordinates */
865 dst_x0 += dst->clip_rect.x;
866 dst_x1 += dst->clip_rect.x;
867 dst_y0 += dst->clip_rect.y;
868 dst_y1 += dst->clip_rect.y;
869
870 final_src.x = (int)SDL_round(src_x0);
871 final_src.y = (int)SDL_round(src_y0);
872 final_src.w = (int)SDL_round(src_x1 - src_x0);
873 final_src.h = (int)SDL_round(src_y1 - src_y0);
874
875 final_dst.x = (int)SDL_round(dst_x0);
876 final_dst.y = (int)SDL_round(dst_y0);
877 final_dst.w = (int)SDL_round(dst_x1 - dst_x0);
878 final_dst.h = (int)SDL_round(dst_y1 - dst_y0);
879
880 /* Clip again */
881 {
882 SDL_Rect tmp;
883 tmp.x = 0;
884 tmp.y = 0;
885 tmp.w = src->w;
886 tmp.h = src->h;
887 SDL_IntersectRect(&tmp, &final_src, &final_src);
888 }
889
890 /* Clip again */
891 SDL_IntersectRect(&dst->clip_rect, &final_dst, &final_dst);
892
893 if (dstrect) {
894 *dstrect = final_dst;
895 }
896
897 if (final_dst.w == 0 || final_dst.h == 0 ||
898 final_src.w <= 0 || final_src.h <= 0) {
899 /* No-op. */
900 return 0;
901 }
902
903 return SDL_PrivateLowerBlitScaled(src, &final_src, dst, &final_dst, scaleMode);
904}
905
906/**
907 * This is a semi-private blit function and it performs low-level surface
908 * scaled blitting only.
909 */
910int
911SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
912 SDL_Surface * dst, SDL_Rect * dstrect)
913{
914 return SDL_PrivateLowerBlitScaled(src, srcrect, dst, dstrect, SDL_ScaleModeNearest);
915}
916
917int
918SDL_PrivateLowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
919 SDL_Surface * dst, SDL_Rect * dstrect, SDL_ScaleMode scaleMode)
920{
921 static const Uint32 complex_copy_flags = (
922 SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
923 SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL |
924 SDL_COPY_COLORKEY
925 );
926
927 if (srcrect->w > SDL_MAX_UINT16 || srcrect->h > SDL_MAX_UINT16 ||
928 dstrect->w > SDL_MAX_UINT16 || dstrect->h > SDL_MAX_UINT16) {
929 return SDL_SetError("Size too large for scaling");
930 }
931
932 if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
933 src->map->info.flags |= SDL_COPY_NEAREST;
934 SDL_InvalidateMap(src->map);
935 }
936
937 if (scaleMode == SDL_ScaleModeNearest) {
938 if ( !(src->map->info.flags & complex_copy_flags) &&
939 src->format->format == dst->format->format &&
940 !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
941 return SDL_SoftStretch( src, srcrect, dst, dstrect );
942 } else {
943 return SDL_LowerBlit( src, srcrect, dst, dstrect );
944 }
945 } else {
946 if ( !(src->map->info.flags & complex_copy_flags) &&
947 src->format->format == dst->format->format &&
948 !SDL_ISPIXELFORMAT_INDEXED(src->format->format) &&
949 src->format->BytesPerPixel == 4 &&
950 src->format->format != SDL_PIXELFORMAT_ARGB2101010) {
951 /* fast path */
952 return SDL_SoftStretchLinear(src, srcrect, dst, dstrect);
953 } else {
954 /* Use intermediate surface(s) */
955 SDL_Surface *tmp1 = NULL;
956 int ret;
957 SDL_Rect srcrect2;
958 int is_complex_copy_flags = (src->map->info.flags & complex_copy_flags);
959
960 Uint32 flags;
961 Uint8 r, g, b;
962 Uint8 alpha;
963 SDL_BlendMode blendMode;
964
965 /* Save source infos */
966 flags = src->flags;
967 SDL_GetSurfaceColorMod(src, &r, &g, &b);
968 SDL_GetSurfaceAlphaMod(src, &alpha);
969 SDL_GetSurfaceBlendMode(src, &blendMode);
970 srcrect2.x = srcrect->x;
971 srcrect2.y = srcrect->y;
972 srcrect2.w = srcrect->w;
973 srcrect2.h = srcrect->h;
974
975 /* Change source format if not appropriate for scaling */
976 if (src->format->BytesPerPixel != 4 || src->format->format == SDL_PIXELFORMAT_ARGB2101010) {
977 SDL_Rect tmprect;
978 int fmt;
979 tmprect.x = 0;
980 tmprect.y = 0;
981 tmprect.w = src->w;
982 tmprect.h = src->h;
983 if (dst->format->BytesPerPixel == 4 && dst->format->format != SDL_PIXELFORMAT_ARGB2101010) {
984 fmt = dst->format->format;
985 } else {
986 fmt = SDL_PIXELFORMAT_ARGB8888;
987 }
988 tmp1 = SDL_CreateRGBSurfaceWithFormat(flags, src->w, src->h, 0, fmt);
989 SDL_LowerBlit(src, srcrect, tmp1, &tmprect);
990
991
992 srcrect2.x = 0;
993 srcrect2.y = 0;
994 SDL_SetSurfaceColorMod(tmp1, r, g, b);
995 SDL_SetSurfaceAlphaMod(tmp1, alpha);
996 SDL_SetSurfaceBlendMode(tmp1, blendMode);
997
998 src = tmp1;
999 }
1000
1001 /* Intermediate scaling */
1002 if (is_complex_copy_flags || src->format->format != dst->format->format) {
1003 SDL_Rect tmprect;
1004 SDL_Surface *tmp2 = SDL_CreateRGBSurfaceWithFormat(flags, dstrect->w, dstrect->h, 0, src->format->format);
1005 SDL_SoftStretchLinear(src, &srcrect2, tmp2, NULL);
1006
1007 SDL_SetSurfaceColorMod(tmp2, r, g, b);
1008 SDL_SetSurfaceAlphaMod(tmp2, alpha);
1009 SDL_SetSurfaceBlendMode(tmp2, blendMode);
1010
1011 tmprect.x = 0;
1012 tmprect.y = 0;
1013 tmprect.w = dstrect->w;
1014 tmprect.h = dstrect->h;
1015 ret = SDL_LowerBlit(tmp2, &tmprect, dst, dstrect);
1016 SDL_FreeSurface(tmp2);
1017 } else {
1018 ret = SDL_SoftStretchLinear(src, &srcrect2, dst, dstrect);
1019 }
1020
1021 SDL_FreeSurface(tmp1);
1022 return ret;
1023 }
1024 }
1025}
1026
1027/*
1028 * Lock a surface to directly access the pixels
1029 */
1030int
1031SDL_LockSurface(SDL_Surface * surface)
1032{
1033 if (!surface->locked) {
1034#if SDL_HAVE_RLE
1035 /* Perform the lock */
1036 if (surface->flags & SDL_RLEACCEL) {
1037 SDL_UnRLESurface(surface, 1);
1038 surface->flags |= SDL_RLEACCEL; /* save accel'd state */
1039 }
1040#endif
1041 }
1042
1043 /* Increment the surface lock count, for recursive locks */
1044 ++surface->locked;
1045
1046 /* Ready to go.. */
1047 return (0);
1048}
1049
1050/*
1051 * Unlock a previously locked surface
1052 */
1053void
1054SDL_UnlockSurface(SDL_Surface * surface)
1055{
1056 /* Only perform an unlock if we are locked */
1057 if (!surface->locked || (--surface->locked > 0)) {
1058 return;
1059 }
1060
1061#if SDL_HAVE_RLE
1062 /* Update RLE encoded surface with new data */
1063 if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
1064 surface->flags &= ~SDL_RLEACCEL; /* stop lying */
1065 SDL_RLESurface(surface);
1066 }
1067#endif
1068}
1069
1070/*
1071 * Creates a new surface identical to the existing surface
1072 */
1073SDL_Surface *
1074SDL_DuplicateSurface(SDL_Surface * surface)
1075{
1076 return SDL_ConvertSurface(surface, surface->format, surface->flags);
1077}
1078
1079/*
1080 * Convert a surface into the specified pixel format.
1081 */
1082SDL_Surface *
1083SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
1084 Uint32 flags)
1085{
1086 SDL_Surface *convert;
1087 Uint32 copy_flags;
1088 SDL_Color copy_color;
1089 SDL_Rect bounds;
1090 int ret;
1091 SDL_bool palette_ck_transform = SDL_FALSE;
1092 int palette_ck_value = 0;
1093 SDL_bool palette_has_alpha = SDL_FALSE;
1094 Uint8 *palette_saved_alpha = NULL;
1095
1096 if (!surface) {
1097 SDL_InvalidParamError("surface");
1098 return NULL;
1099 }
1100 if (!format) {
1101 SDL_InvalidParamError("format");
1102 return NULL;
1103 }
1104
1105 /* Check for empty destination palette! (results in empty image) */
1106 if (format->palette != NULL) {
1107 int i;
1108 for (i = 0; i < format->palette->ncolors; ++i) {
1109 if ((format->palette->colors[i].r != 0xFF) ||
1110 (format->palette->colors[i].g != 0xFF) ||
1111 (format->palette->colors[i].b != 0xFF))
1112 break;
1113 }
1114 if (i == format->palette->ncolors) {
1115 SDL_SetError("Empty destination palette");
1116 return (NULL);
1117 }
1118 }
1119
1120 /* Create a new surface with the desired format */
1121 convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
1122 format->BitsPerPixel, format->Rmask,
1123 format->Gmask, format->Bmask,
1124 format->Amask);
1125 if (convert == NULL) {
1126 return (NULL);
1127 }
1128
1129 /* Copy the palette if any */
1130 if (format->palette && convert->format->palette) {
1131 SDL_memcpy(convert->format->palette->colors,
1132 format->palette->colors,
1133 format->palette->ncolors * sizeof(SDL_Color));
1134 convert->format->palette->ncolors = format->palette->ncolors;
1135 }
1136
1137 /* Save the original copy flags */
1138 copy_flags = surface->map->info.flags;
1139 copy_color.r = surface->map->info.r;
1140 copy_color.g = surface->map->info.g;
1141 copy_color.b = surface->map->info.b;
1142 copy_color.a = surface->map->info.a;
1143 surface->map->info.r = 0xFF;
1144 surface->map->info.g = 0xFF;
1145 surface->map->info.b = 0xFF;
1146 surface->map->info.a = 0xFF;
1147 surface->map->info.flags = (copy_flags & (SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY));
1148 SDL_InvalidateMap(surface->map);
1149
1150 /* Copy over the image data */
1151 bounds.x = 0;
1152 bounds.y = 0;
1153 bounds.w = surface->w;
1154 bounds.h = surface->h;
1155
1156 /* Source surface has a palette with no real alpha (0 or OPAQUE).
1157 * Destination format has alpha.
1158 * -> set alpha channel to be opaque */
1159 if (surface->format->palette && format->Amask) {
1160 SDL_bool set_opaque = SDL_FALSE;
1161
1162 SDL_bool is_opaque, has_alpha_channel;
1163 SDL_DetectPalette(surface->format->palette, &is_opaque, &has_alpha_channel);
1164
1165 if (is_opaque) {
1166 if (!has_alpha_channel) {
1167 set_opaque = SDL_TRUE;
1168 }
1169 } else {
1170 palette_has_alpha = SDL_TRUE;
1171 }
1172
1173 /* Set opaque and backup palette alpha values */
1174 if (set_opaque) {
1175 int i;
1176 palette_saved_alpha = SDL_stack_alloc(Uint8, surface->format->palette->ncolors);
1177 for (i = 0; i < surface->format->palette->ncolors; i++) {
1178 palette_saved_alpha[i] = surface->format->palette->colors[i].a;
1179 surface->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
1180 }
1181 }
1182 }
1183
1184 /* Transform colorkey to alpha. for cases where source palette has duplicate values, and colorkey is one of them */
1185 if (copy_flags & SDL_COPY_COLORKEY) {
1186 if (surface->format->palette && !format->palette) {
1187 palette_ck_transform = SDL_TRUE;
1188 palette_has_alpha = SDL_TRUE;
1189 palette_ck_value = surface->format->palette->colors[surface->map->info.colorkey].a;
1190 surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
1191 }
1192 }
1193
1194 ret = SDL_LowerBlit(surface, &bounds, convert, &bounds);
1195
1196 /* Restore colorkey alpha value */
1197 if (palette_ck_transform) {
1198 surface->format->palette->colors[surface->map->info.colorkey].a = palette_ck_value;
1199 }
1200
1201 /* Restore palette alpha values */
1202 if (palette_saved_alpha) {
1203 int i;
1204 for (i = 0; i < surface->format->palette->ncolors; i++) {
1205 surface->format->palette->colors[i].a = palette_saved_alpha[i];
1206 }
1207 SDL_stack_free(palette_saved_alpha);
1208 }
1209
1210 /* Clean up the original surface, and update converted surface */
1211 convert->map->info.r = copy_color.r;
1212 convert->map->info.g = copy_color.g;
1213 convert->map->info.b = copy_color.b;
1214 convert->map->info.a = copy_color.a;
1215 convert->map->info.flags =
1216 (copy_flags &
1217 ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
1218 | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
1219 SDL_COPY_RLE_ALPHAKEY));
1220 surface->map->info.r = copy_color.r;
1221 surface->map->info.g = copy_color.g;
1222 surface->map->info.b = copy_color.b;
1223 surface->map->info.a = copy_color.a;
1224 surface->map->info.flags = copy_flags;
1225 SDL_InvalidateMap(surface->map);
1226
1227 /* SDL_LowerBlit failed, and so the conversion */
1228 if (ret < 0) {
1229 SDL_FreeSurface(convert);
1230 return NULL;
1231 }
1232
1233 if (copy_flags & SDL_COPY_COLORKEY) {
1234 SDL_bool set_colorkey_by_color = SDL_FALSE;
1235 SDL_bool convert_colorkey = SDL_TRUE;
1236
1237 if (surface->format->palette) {
1238 if (format->palette &&
1239 surface->format->palette->ncolors <= format->palette->ncolors &&
1240 (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
1241 surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
1242 /* The palette is identical, just set the same colorkey */
1243 SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
1244 } else if (!format->palette) {
1245 if (format->Amask) {
1246 /* No need to add the colorkey, transparency is in the alpha channel*/
1247 } else {
1248 /* Only set the colorkey information */
1249 set_colorkey_by_color = SDL_TRUE;
1250 convert_colorkey = SDL_FALSE;
1251 }
1252 } else {
1253 set_colorkey_by_color = SDL_TRUE;
1254 }
1255 } else {
1256 set_colorkey_by_color = SDL_TRUE;
1257 }
1258
1259 if (set_colorkey_by_color) {
1260 SDL_Surface *tmp;
1261 SDL_Surface *tmp2;
1262 int converted_colorkey = 0;
1263
1264 /* Create a dummy surface to get the colorkey converted */
1265 tmp = SDL_CreateRGBSurface(0, 1, 1,
1266 surface->format->BitsPerPixel, surface->format->Rmask,
1267 surface->format->Gmask, surface->format->Bmask,
1268 surface->format->Amask);
1269
1270 /* Share the palette, if any */
1271 if (surface->format->palette) {
1272 SDL_SetSurfacePalette(tmp, surface->format->palette);
1273 }
1274
1275 SDL_FillRect(tmp, NULL, surface->map->info.colorkey);
1276
1277 tmp->map->info.flags &= ~SDL_COPY_COLORKEY;
1278
1279 /* Convertion of the colorkey */
1280 tmp2 = SDL_ConvertSurface(tmp, format, 0);
1281
1282 /* Get the converted colorkey */
1283 SDL_memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel);
1284
1285 SDL_FreeSurface(tmp);
1286 SDL_FreeSurface(tmp2);
1287
1288 /* Set the converted colorkey on the new surface */
1289 SDL_SetColorKey(convert, 1, converted_colorkey);
1290
1291 /* This is needed when converting for 3D texture upload */
1292 if (convert_colorkey) {
1293 SDL_ConvertColorkeyToAlpha(convert, SDL_TRUE);
1294 }
1295 }
1296 }
1297 SDL_SetClipRect(convert, &surface->clip_rect);
1298
1299 /* Enable alpha blending by default if the new surface has an
1300 * alpha channel or alpha modulation */
1301 if ((surface->format->Amask && format->Amask) ||
1302 (palette_has_alpha && format->Amask) ||
1303 (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
1304 SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
1305 }
1306 if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
1307 SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
1308 }
1309
1310 /* We're ready to go! */
1311 return (convert);
1312}
1313
1314SDL_Surface *
1315SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
1316 Uint32 flags)
1317{
1318 SDL_PixelFormat *fmt;
1319 SDL_Surface *convert = NULL;
1320
1321 fmt = SDL_AllocFormat(pixel_format);
1322 if (fmt) {
1323 convert = SDL_ConvertSurface(surface, fmt, flags);
1324 SDL_FreeFormat(fmt);
1325 }
1326 return convert;
1327}
1328
1329/*
1330 * Create a surface on the stack for quick blit operations
1331 */
1332static SDL_INLINE SDL_bool
1333SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
1334 void * pixels, int pitch, SDL_Surface * surface,
1335 SDL_PixelFormat * format, SDL_BlitMap * blitmap)
1336{
1337 if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
1338 SDL_SetError("Indexed pixel formats not supported");
1339 return SDL_FALSE;
1340 }
1341 if (SDL_InitFormat(format, pixel_format) < 0) {
1342 return SDL_FALSE;
1343 }
1344
1345 SDL_zerop(surface);
1346 surface->flags = SDL_PREALLOC;
1347 surface->format = format;
1348 surface->pixels = pixels;
1349 surface->w = width;
1350 surface->h = height;
1351 surface->pitch = pitch;
1352 /* We don't actually need to set up the clip rect for our purposes */
1353 /* SDL_SetClipRect(surface, NULL); */
1354
1355 /* Allocate an empty mapping */
1356 SDL_zerop(blitmap);
1357 blitmap->info.r = 0xFF;
1358 blitmap->info.g = 0xFF;
1359 blitmap->info.b = 0xFF;
1360 blitmap->info.a = 0xFF;
1361 surface->map = blitmap;
1362
1363 /* The surface is ready to go */
1364 surface->refcount = 1;
1365 return SDL_TRUE;
1366}
1367
1368/*
1369 * Copy a block of pixels of one format to another format
1370 */
1371int SDL_ConvertPixels(int width, int height,
1372 Uint32 src_format, const void * src, int src_pitch,
1373 Uint32 dst_format, void * dst, int dst_pitch)
1374{
1375 SDL_Surface src_surface, dst_surface;
1376 SDL_PixelFormat src_fmt, dst_fmt;
1377 SDL_BlitMap src_blitmap, dst_blitmap;
1378 SDL_Rect rect;
1379 void *nonconst_src = (void *) src;
1380 int ret;
1381
1382 /* Check to make sure we are blitting somewhere, so we don't crash */
1383 if (!dst) {
1384 return SDL_InvalidParamError("dst");
1385 }
1386 if (!dst_pitch) {
1387 return SDL_InvalidParamError("dst_pitch");
1388 }
1389
1390#if SDL_HAVE_YUV
1391 if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1392 return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1393 } else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
1394 return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1395 } else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1396 return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1397 }
1398#else
1399 if (SDL_ISPIXELFORMAT_FOURCC(src_format) || SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1400 SDL_SetError("SDL not built with YUV support");
1401 return -1;
1402 }
1403#endif
1404
1405 /* Fast path for same format copy */
1406 if (src_format == dst_format) {
1407 int i;
1408 const int bpp = SDL_BYTESPERPIXEL(src_format);
1409 width *= bpp;
1410 for (i = height; i--;) {
1411 SDL_memcpy(dst, src, width);
1412 src = (const Uint8*)src + src_pitch;
1413 dst = (Uint8*)dst + dst_pitch;
1414 }
1415 return 0;
1416 }
1417
1418 if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
1419 src_pitch,
1420 &src_surface, &src_fmt, &src_blitmap)) {
1421 return -1;
1422 }
1423 if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
1424 &dst_surface, &dst_fmt, &dst_blitmap)) {
1425 return -1;
1426 }
1427
1428 /* Set up the rect and go! */
1429 rect.x = 0;
1430 rect.y = 0;
1431 rect.w = width;
1432 rect.h = height;
1433 ret = SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
1434
1435 /* Free blitmap reference, after blitting between stack'ed surfaces */
1436 SDL_InvalidateMap(src_surface.map);
1437
1438 return ret;
1439}
1440
1441/*
1442 * Free a surface created by the above function.
1443 */
1444void
1445SDL_FreeSurface(SDL_Surface * surface)
1446{
1447 if (surface == NULL) {
1448 return;
1449 }
1450 if (surface->flags & SDL_DONTFREE) {
1451 return;
1452 }
1453 SDL_InvalidateMap(surface->map);
1454
1455 SDL_InvalidateAllBlitMap(surface);
1456
1457 if (--surface->refcount > 0) {
1458 return;
1459 }
1460 while (surface->locked > 0) {
1461 SDL_UnlockSurface(surface);
1462 }
1463#if SDL_HAVE_RLE
1464 if (surface->flags & SDL_RLEACCEL) {
1465 SDL_UnRLESurface(surface, 0);
1466 }
1467#endif
1468 if (surface->format) {
1469 SDL_SetSurfacePalette(surface, NULL);
1470 SDL_FreeFormat(surface->format);
1471 surface->format = NULL;
1472 }
1473 if (surface->flags & SDL_PREALLOC) {
1474 /* Don't free */
1475 } else if (surface->flags & SDL_SIMD_ALIGNED) {
1476 /* Free aligned */
1477 SDL_SIMDFree(surface->pixels);
1478 } else {
1479 /* Normal */
1480 SDL_free(surface->pixels);
1481 }
1482 if (surface->map) {
1483 SDL_FreeBlitMap(surface->map);
1484 }
1485 SDL_free(surface);
1486}
1487
1488/* vi: set ts=4 sw=4 expandtab: */
1489