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