SDL  2.0
SDL_surface.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 
29 /* Public routines */
30 /*
31  * Create an empty RGB surface of the appropriate depth
32  */
35  int width, int height, int depth,
36  Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
37 {
38  SDL_Surface *surface;
39  Uint32 format;
40 
41  /* The flags are no longer used, make the compiler happy */
42  (void)flags;
43 
44  /* Get the pixel format */
45  format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
46  if (format == SDL_PIXELFORMAT_UNKNOWN) {
47  SDL_SetError("Unknown pixel format");
48  return NULL;
49  }
50 
51  /* Allocate the surface */
52  surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
53  if (surface == NULL) {
55  return NULL;
56  }
57 
58  surface->format = SDL_AllocFormat(format);
59  if (!surface->format) {
60  SDL_FreeSurface(surface);
61  return NULL;
62  }
63  surface->w = width;
64  surface->h = height;
65  surface->pitch = SDL_CalculatePitch(surface);
66  SDL_SetClipRect(surface, NULL);
67 
68  if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
69  SDL_Palette *palette =
70  SDL_AllocPalette((1 << surface->format->BitsPerPixel));
71  if (!palette) {
72  SDL_FreeSurface(surface);
73  return NULL;
74  }
75  if (palette->ncolors == 2) {
76  /* Create a black and white bitmap palette */
77  palette->colors[0].r = 0xFF;
78  palette->colors[0].g = 0xFF;
79  palette->colors[0].b = 0xFF;
80  palette->colors[1].r = 0x00;
81  palette->colors[1].g = 0x00;
82  palette->colors[1].b = 0x00;
83  }
84  SDL_SetSurfacePalette(surface, palette);
85  SDL_FreePalette(palette);
86  }
87 
88  /* Get the pixels */
89  if (surface->w && surface->h) {
90  surface->pixels = SDL_malloc(surface->h * surface->pitch);
91  if (!surface->pixels) {
92  SDL_FreeSurface(surface);
94  return NULL;
95  }
96  /* This is important for bitmaps */
97  SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
98  }
99 
100  /* Allocate an empty mapping */
101  surface->map = SDL_AllocBlitMap();
102  if (!surface->map) {
103  SDL_FreeSurface(surface);
104  return NULL;
105  }
106 
107  /* By default surface with an alpha mask are set up for blending */
108  if (Amask) {
110  }
111 
112  /* The surface is ready to go */
113  surface->refcount = 1;
114  return surface;
115 }
116 
117 /*
118  * Create an RGB surface from an existing memory buffer
119  */
120 SDL_Surface *
122  int width, int height, int depth, int pitch,
123  Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
124  Uint32 Amask)
125 {
126  SDL_Surface *surface;
127 
128  surface =
129  SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
130  if (surface != NULL) {
131  surface->flags |= SDL_PREALLOC;
132  surface->pixels = pixels;
133  surface->w = width;
134  surface->h = height;
135  surface->pitch = pitch;
136  SDL_SetClipRect(surface, NULL);
137  }
138  return surface;
139 }
140 
141 int
143 {
144  if (!surface) {
145  return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
146  }
147  if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) {
148  return -1;
149  }
150  SDL_InvalidateMap(surface->map);
151 
152  return 0;
153 }
154 
155 int
156 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
157 {
158  int flags;
159 
160  if (!surface) {
161  return -1;
162  }
163 
164  flags = surface->map->info.flags;
165  if (flag) {
166  surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
167  } else {
168  surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
169  }
170  if (surface->map->info.flags != flags) {
171  SDL_InvalidateMap(surface->map);
172  }
173  return 0;
174 }
175 
176 int
177 SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
178 {
179  int flags;
180 
181  if (!surface) {
182  return SDL_InvalidParamError("surface");
183  }
184 
185  if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
186  return SDL_InvalidParamError("key");
187  }
188 
189  if (flag & SDL_RLEACCEL) {
190  SDL_SetSurfaceRLE(surface, 1);
191  }
192 
193  flags = surface->map->info.flags;
194  if (flag) {
195  surface->map->info.flags |= SDL_COPY_COLORKEY;
196  surface->map->info.colorkey = key;
197  if (surface->format->palette) {
198  surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
199  ++surface->format->palette->version;
200  if (!surface->format->palette->version) {
201  surface->format->palette->version = 1;
202  }
203  }
204  } else {
205  if (surface->format->palette) {
206  surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_OPAQUE;
207  ++surface->format->palette->version;
208  if (!surface->format->palette->version) {
209  surface->format->palette->version = 1;
210  }
211  }
212  surface->map->info.flags &= ~SDL_COPY_COLORKEY;
213  }
214  if (surface->map->info.flags != flags) {
215  SDL_InvalidateMap(surface->map);
216  }
217 
218  return 0;
219 }
220 
221 int
223 {
224  if (!surface) {
225  return -1;
226  }
227 
228  if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
229  return -1;
230  }
231 
232  if (key) {
233  *key = surface->map->info.colorkey;
234  }
235  return 0;
236 }
237 
238 /* This is a fairly slow function to switch from colorkey to alpha */
239 static void
241 {
242  int x, y;
243 
244  if (!surface) {
245  return;
246  }
247 
248  if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
249  !surface->format->Amask) {
250  return;
251  }
252 
253  SDL_LockSurface(surface);
254 
255  switch (surface->format->BytesPerPixel) {
256  case 2:
257  {
258  Uint16 *row, *spot;
259  Uint16 ckey = (Uint16) surface->map->info.colorkey;
260  Uint16 mask = (Uint16) (~surface->format->Amask);
261 
262  /* Ignore alpha in colorkey comparison */
263  ckey &= mask;
264  row = (Uint16 *) surface->pixels;
265  for (y = surface->h; y--;) {
266  spot = row;
267  for (x = surface->w; x--;) {
268  if ((*spot & mask) == ckey) {
269  *spot &= mask;
270  }
271  ++spot;
272  }
273  row += surface->pitch / 2;
274  }
275  }
276  break;
277  case 3:
278  /* FIXME */
279  break;
280  case 4:
281  {
282  Uint32 *row, *spot;
283  Uint32 ckey = surface->map->info.colorkey;
284  Uint32 mask = ~surface->format->Amask;
285 
286  /* Ignore alpha in colorkey comparison */
287  ckey &= mask;
288  row = (Uint32 *) surface->pixels;
289  for (y = surface->h; y--;) {
290  spot = row;
291  for (x = surface->w; x--;) {
292  if ((*spot & mask) == ckey) {
293  *spot &= mask;
294  }
295  ++spot;
296  }
297  row += surface->pitch / 4;
298  }
299  }
300  break;
301  }
302 
303  SDL_UnlockSurface(surface);
304 
305  SDL_SetColorKey(surface, 0, 0);
307 }
308 
309 int
311 {
312  int flags;
313 
314  if (!surface) {
315  return -1;
316  }
317 
318  surface->map->info.r = r;
319  surface->map->info.g = g;
320  surface->map->info.b = b;
321 
322  flags = surface->map->info.flags;
323  if (r != 0xFF || g != 0xFF || b != 0xFF) {
324  surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
325  } else {
326  surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
327  }
328  if (surface->map->info.flags != flags) {
329  SDL_InvalidateMap(surface->map);
330  }
331  return 0;
332 }
333 
334 
335 int
337 {
338  if (!surface) {
339  return -1;
340  }
341 
342  if (r) {
343  *r = surface->map->info.r;
344  }
345  if (g) {
346  *g = surface->map->info.g;
347  }
348  if (b) {
349  *b = surface->map->info.b;
350  }
351  return 0;
352 }
353 
354 int
356 {
357  int flags;
358 
359  if (!surface) {
360  return -1;
361  }
362 
363  surface->map->info.a = alpha;
364 
365  flags = surface->map->info.flags;
366  if (alpha != 0xFF) {
367  surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
368  } else {
369  surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
370  }
371  if (surface->map->info.flags != flags) {
372  SDL_InvalidateMap(surface->map);
373  }
374  return 0;
375 }
376 
377 int
379 {
380  if (!surface) {
381  return -1;
382  }
383 
384  if (alpha) {
385  *alpha = surface->map->info.a;
386  }
387  return 0;
388 }
389 
390 int
392 {
393  int flags, status;
394 
395  if (!surface) {
396  return -1;
397  }
398 
399  status = 0;
400  flags = surface->map->info.flags;
401  surface->map->info.flags &=
403  switch (blendMode) {
404  case SDL_BLENDMODE_NONE:
405  break;
406  case SDL_BLENDMODE_BLEND:
407  surface->map->info.flags |= SDL_COPY_BLEND;
408  break;
409  case SDL_BLENDMODE_ADD:
410  surface->map->info.flags |= SDL_COPY_ADD;
411  break;
412  case SDL_BLENDMODE_MOD:
413  surface->map->info.flags |= SDL_COPY_MOD;
414  break;
415  default:
416  status = SDL_Unsupported();
417  break;
418  }
419 
420  if (surface->map->info.flags != flags) {
421  SDL_InvalidateMap(surface->map);
422  }
423 
424  return status;
425 }
426 
427 int
429 {
430  if (!surface) {
431  return -1;
432  }
433 
434  if (!blendMode) {
435  return 0;
436  }
437 
438  switch (surface->map->
439  info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD)) {
440  case SDL_COPY_BLEND:
441  *blendMode = SDL_BLENDMODE_BLEND;
442  break;
443  case SDL_COPY_ADD:
444  *blendMode = SDL_BLENDMODE_ADD;
445  break;
446  case SDL_COPY_MOD:
447  *blendMode = SDL_BLENDMODE_MOD;
448  break;
449  default:
450  *blendMode = SDL_BLENDMODE_NONE;
451  break;
452  }
453  return 0;
454 }
455 
456 SDL_bool
458 {
459  SDL_Rect full_rect;
460 
461  /* Don't do anything if there's no surface to act on */
462  if (!surface) {
463  return SDL_FALSE;
464  }
465 
466  /* Set up the full surface rectangle */
467  full_rect.x = 0;
468  full_rect.y = 0;
469  full_rect.w = surface->w;
470  full_rect.h = surface->h;
471 
472  /* Set the clipping rectangle */
473  if (!rect) {
474  surface->clip_rect = full_rect;
475  return SDL_TRUE;
476  }
477  return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
478 }
479 
480 void
482 {
483  if (surface && rect) {
484  *rect = surface->clip_rect;
485  }
486 }
487 
488 /*
489  * Set up a blit between two surfaces -- split into three parts:
490  * The upper part, SDL_UpperBlit(), performs clipping and rectangle
491  * verification. The lower part is a pointer to a low level
492  * accelerated blitting function.
493  *
494  * These parts are separated out and each used internally by this
495  * library in the optimimum places. They are exported so that if
496  * you know exactly what you are doing, you can optimize your code
497  * by calling the one(s) you need.
498  */
499 int
501  SDL_Surface * dst, SDL_Rect * dstrect)
502 {
503  /* Check to make sure the blit mapping is valid */
504  if ((src->map->dst != dst) ||
505  (dst->format->palette &&
506  src->map->dst_palette_version != dst->format->palette->version) ||
507  (src->format->palette &&
508  src->map->src_palette_version != src->format->palette->version)) {
509  if (SDL_MapSurface(src, dst) < 0) {
510  return (-1);
511  }
512  /* just here for debugging */
513 /* printf */
514 /* ("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", */
515 /* src, dst->flags, src->map->info.flags, dst, dst->flags, */
516 /* dst->map->info.flags, src->map->blit); */
517  }
518  return (src->map->blit(src, srcrect, dst, dstrect));
519 }
520 
521 
522 int
524  SDL_Surface * dst, SDL_Rect * dstrect)
525 {
526  SDL_Rect fulldst;
527  int srcx, srcy, w, h;
528 
529  /* Make sure the surfaces aren't locked */
530  if (!src || !dst) {
531  return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
532  }
533  if (src->locked || dst->locked) {
534  return SDL_SetError("Surfaces must not be locked during blit");
535  }
536 
537  /* If the destination rectangle is NULL, use the entire dest surface */
538  if (dstrect == NULL) {
539  fulldst.x = fulldst.y = 0;
540  fulldst.w = dst->w;
541  fulldst.h = dst->h;
542  dstrect = &fulldst;
543  }
544 
545  /* clip the source rectangle to the source surface */
546  if (srcrect) {
547  int maxw, maxh;
548 
549  srcx = srcrect->x;
550  w = srcrect->w;
551  if (srcx < 0) {
552  w += srcx;
553  dstrect->x -= srcx;
554  srcx = 0;
555  }
556  maxw = src->w - srcx;
557  if (maxw < w)
558  w = maxw;
559 
560  srcy = srcrect->y;
561  h = srcrect->h;
562  if (srcy < 0) {
563  h += srcy;
564  dstrect->y -= srcy;
565  srcy = 0;
566  }
567  maxh = src->h - srcy;
568  if (maxh < h)
569  h = maxh;
570 
571  } else {
572  srcx = srcy = 0;
573  w = src->w;
574  h = src->h;
575  }
576 
577  /* clip the destination rectangle against the clip rectangle */
578  {
579  SDL_Rect *clip = &dst->clip_rect;
580  int dx, dy;
581 
582  dx = clip->x - dstrect->x;
583  if (dx > 0) {
584  w -= dx;
585  dstrect->x += dx;
586  srcx += dx;
587  }
588  dx = dstrect->x + w - clip->x - clip->w;
589  if (dx > 0)
590  w -= dx;
591 
592  dy = clip->y - dstrect->y;
593  if (dy > 0) {
594  h -= dy;
595  dstrect->y += dy;
596  srcy += dy;
597  }
598  dy = dstrect->y + h - clip->y - clip->h;
599  if (dy > 0)
600  h -= dy;
601  }
602 
603  /* Switch back to a fast blit if we were previously stretching */
604  if (src->map->info.flags & SDL_COPY_NEAREST) {
605  src->map->info.flags &= ~SDL_COPY_NEAREST;
606  SDL_InvalidateMap(src->map);
607  }
608 
609  if (w > 0 && h > 0) {
610  SDL_Rect sr;
611  sr.x = srcx;
612  sr.y = srcy;
613  sr.w = dstrect->w = w;
614  sr.h = dstrect->h = h;
615  return SDL_LowerBlit(src, &sr, dst, dstrect);
616  }
617  dstrect->w = dstrect->h = 0;
618  return 0;
619 }
620 
621 int
623  SDL_Surface * dst, SDL_Rect * dstrect)
624 {
625  double src_x0, src_y0, src_x1, src_y1;
626  double dst_x0, dst_y0, dst_x1, dst_y1;
627  SDL_Rect final_src, final_dst;
628  double scaling_w, scaling_h;
629  int src_w, src_h;
630  int dst_w, dst_h;
631 
632  /* Make sure the surfaces aren't locked */
633  if (!src || !dst) {
634  return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
635  }
636  if (src->locked || dst->locked) {
637  return SDL_SetError("Surfaces must not be locked during blit");
638  }
639 
640  if (NULL == srcrect) {
641  src_w = src->w;
642  src_h = src->h;
643  } else {
644  src_w = srcrect->w;
645  src_h = srcrect->h;
646  }
647 
648  if (NULL == dstrect) {
649  dst_w = dst->w;
650  dst_h = dst->h;
651  } else {
652  dst_w = dstrect->w;
653  dst_h = dstrect->h;
654  }
655 
656  if (dst_w == src_w && dst_h == src_h) {
657  /* No scaling, defer to regular blit */
658  return SDL_BlitSurface(src, srcrect, dst, dstrect);
659  }
660 
661  scaling_w = (double)dst_w / src_w;
662  scaling_h = (double)dst_h / src_h;
663 
664  if (NULL == dstrect) {
665  dst_x0 = 0;
666  dst_y0 = 0;
667  dst_x1 = dst_w - 1;
668  dst_y1 = dst_h - 1;
669  } else {
670  dst_x0 = dstrect->x;
671  dst_y0 = dstrect->y;
672  dst_x1 = dst_x0 + dst_w - 1;
673  dst_y1 = dst_y0 + dst_h - 1;
674  }
675 
676  if (NULL == srcrect) {
677  src_x0 = 0;
678  src_y0 = 0;
679  src_x1 = src_w - 1;
680  src_y1 = src_h - 1;
681  } else {
682  src_x0 = srcrect->x;
683  src_y0 = srcrect->y;
684  src_x1 = src_x0 + src_w - 1;
685  src_y1 = src_y0 + src_h - 1;
686 
687  /* Clip source rectangle to the source surface */
688 
689  if (src_x0 < 0) {
690  dst_x0 -= src_x0 * scaling_w;
691  src_x0 = 0;
692  }
693 
694  if (src_x1 >= src->w) {
695  dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
696  src_x1 = src->w - 1;
697  }
698 
699  if (src_y0 < 0) {
700  dst_y0 -= src_y0 * scaling_h;
701  src_y0 = 0;
702  }
703 
704  if (src_y1 >= src->h) {
705  dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
706  src_y1 = src->h - 1;
707  }
708  }
709 
710  /* Clip destination rectangle to the clip rectangle */
711 
712  /* Translate to clip space for easier calculations */
713  dst_x0 -= dst->clip_rect.x;
714  dst_x1 -= dst->clip_rect.x;
715  dst_y0 -= dst->clip_rect.y;
716  dst_y1 -= dst->clip_rect.y;
717 
718  if (dst_x0 < 0) {
719  src_x0 -= dst_x0 / scaling_w;
720  dst_x0 = 0;
721  }
722 
723  if (dst_x1 >= dst->clip_rect.w) {
724  src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
725  dst_x1 = dst->clip_rect.w - 1;
726  }
727 
728  if (dst_y0 < 0) {
729  src_y0 -= dst_y0 / scaling_h;
730  dst_y0 = 0;
731  }
732 
733  if (dst_y1 >= dst->clip_rect.h) {
734  src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
735  dst_y1 = dst->clip_rect.h - 1;
736  }
737 
738  /* Translate back to surface coordinates */
739  dst_x0 += dst->clip_rect.x;
740  dst_x1 += dst->clip_rect.x;
741  dst_y0 += dst->clip_rect.y;
742  dst_y1 += dst->clip_rect.y;
743 
744  final_src.x = (int)SDL_floor(src_x0 + 0.5);
745  final_src.y = (int)SDL_floor(src_y0 + 0.5);
746  final_src.w = (int)SDL_floor(src_x1 - src_x0 + 1.5);
747  final_src.h = (int)SDL_floor(src_y1 - src_y0 + 1.5);
748 
749  final_dst.x = (int)SDL_floor(dst_x0 + 0.5);
750  final_dst.y = (int)SDL_floor(dst_y0 + 0.5);
751  final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5);
752  final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5);
753 
754  if (final_dst.w < 0)
755  final_dst.w = 0;
756  if (final_dst.h < 0)
757  final_dst.h = 0;
758 
759  if (dstrect)
760  *dstrect = final_dst;
761 
762  if (final_dst.w == 0 || final_dst.h == 0 ||
763  final_src.w <= 0 || final_src.h <= 0) {
764  /* No-op. */
765  return 0;
766  }
767 
768  return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
769 }
770 
771 /**
772  * This is a semi-private blit function and it performs low-level surface
773  * scaled blitting only.
774  */
775 int
777  SDL_Surface * dst, SDL_Rect * dstrect)
778 {
779  static const Uint32 complex_copy_flags = (
783  );
784 
785  if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
786  src->map->info.flags |= SDL_COPY_NEAREST;
787  SDL_InvalidateMap(src->map);
788  }
789 
790  if ( !(src->map->info.flags & complex_copy_flags) &&
791  src->format->format == dst->format->format &&
793  return SDL_SoftStretch( src, srcrect, dst, dstrect );
794  } else {
795  return SDL_LowerBlit( src, srcrect, dst, dstrect );
796  }
797 }
798 
799 /*
800  * Lock a surface to directly access the pixels
801  */
802 int
804 {
805  if (!surface->locked) {
806  /* Perform the lock */
807  if (surface->flags & SDL_RLEACCEL) {
808  SDL_UnRLESurface(surface, 1);
809  surface->flags |= SDL_RLEACCEL; /* save accel'd state */
810  }
811  }
812 
813  /* Increment the surface lock count, for recursive locks */
814  ++surface->locked;
815 
816  /* Ready to go.. */
817  return (0);
818 }
819 
820 /*
821  * Unlock a previously locked surface
822  */
823 void
825 {
826  /* Only perform an unlock if we are locked */
827  if (!surface->locked || (--surface->locked > 0)) {
828  return;
829  }
830 
831  /* Update RLE encoded surface with new data */
832  if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
833  surface->flags &= ~SDL_RLEACCEL; /* stop lying */
834  SDL_RLESurface(surface);
835  }
836 }
837 
838 /*
839  * Convert a surface into the specified pixel format.
840  */
841 SDL_Surface *
843  Uint32 flags)
844 {
845  SDL_Surface *convert;
846  Uint32 copy_flags;
847  SDL_Color copy_color;
848  SDL_Rect bounds;
849 
850  /* Check for empty destination palette! (results in empty image) */
851  if (format->palette != NULL) {
852  int i;
853  for (i = 0; i < format->palette->ncolors; ++i) {
854  if ((format->palette->colors[i].r != 0xFF) ||
855  (format->palette->colors[i].g != 0xFF) ||
856  (format->palette->colors[i].b != 0xFF))
857  break;
858  }
859  if (i == format->palette->ncolors) {
860  SDL_SetError("Empty destination palette");
861  return (NULL);
862  }
863  }
864 
865  /* Create a new surface with the desired format */
866  convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
867  format->BitsPerPixel, format->Rmask,
868  format->Gmask, format->Bmask,
869  format->Amask);
870  if (convert == NULL) {
871  return (NULL);
872  }
873 
874  /* Copy the palette if any */
875  if (format->palette && convert->format->palette) {
876  SDL_memcpy(convert->format->palette->colors,
877  format->palette->colors,
878  format->palette->ncolors * sizeof(SDL_Color));
879  convert->format->palette->ncolors = format->palette->ncolors;
880  }
881 
882  /* Save the original copy flags */
883  copy_flags = surface->map->info.flags;
884  copy_color.r = surface->map->info.r;
885  copy_color.g = surface->map->info.g;
886  copy_color.b = surface->map->info.b;
887  copy_color.a = surface->map->info.a;
888  surface->map->info.r = 0xFF;
889  surface->map->info.g = 0xFF;
890  surface->map->info.b = 0xFF;
891  surface->map->info.a = 0xFF;
892  surface->map->info.flags = 0;
893  SDL_InvalidateMap(surface->map);
894 
895  /* Copy over the image data */
896  bounds.x = 0;
897  bounds.y = 0;
898  bounds.w = surface->w;
899  bounds.h = surface->h;
900  SDL_LowerBlit(surface, &bounds, convert, &bounds);
901 
902  /* Clean up the original surface, and update converted surface */
903  convert->map->info.r = copy_color.r;
904  convert->map->info.g = copy_color.g;
905  convert->map->info.b = copy_color.b;
906  convert->map->info.a = copy_color.a;
907  convert->map->info.flags =
908  (copy_flags &
912  surface->map->info.r = copy_color.r;
913  surface->map->info.g = copy_color.g;
914  surface->map->info.b = copy_color.b;
915  surface->map->info.a = copy_color.a;
916  surface->map->info.flags = copy_flags;
917  SDL_InvalidateMap(surface->map);
918  if (copy_flags & SDL_COPY_COLORKEY) {
919  SDL_bool set_colorkey_by_color = SDL_FALSE;
920 
921  if (surface->format->palette) {
922  if (format->palette &&
923  surface->format->palette->ncolors <= format->palette->ncolors &&
924  (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
925  surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
926  /* The palette is identical, just set the same colorkey */
927  SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
928  } else if (format->Amask) {
929  /* The alpha was set in the destination from the palette */
930  } else {
931  set_colorkey_by_color = SDL_TRUE;
932  }
933  } else {
934  set_colorkey_by_color = SDL_TRUE;
935  }
936 
937  if (set_colorkey_by_color) {
938  /* Set the colorkey by color, which needs to be unique */
939  Uint8 keyR, keyG, keyB, keyA;
940 
941  SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
942  &keyG, &keyB, &keyA);
943  SDL_SetColorKey(convert, 1,
944  SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
945  /* This is needed when converting for 3D texture upload */
947  }
948  }
949  SDL_SetClipRect(convert, &surface->clip_rect);
950 
951  /* Enable alpha blending by default if the new surface has an
952  * alpha channel or alpha modulation */
953  if ((surface->format->Amask && format->Amask) ||
954  (copy_flags & (SDL_COPY_COLORKEY|SDL_COPY_MODULATE_ALPHA))) {
956  }
957  if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
958  SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
959  }
960 
961  /* We're ready to go! */
962  return (convert);
963 }
964 
965 SDL_Surface *
967  Uint32 flags)
968 {
969  SDL_PixelFormat *fmt;
970  SDL_Surface *convert = NULL;
971 
972  fmt = SDL_AllocFormat(pixel_format);
973  if (fmt) {
974  convert = SDL_ConvertSurface(surface, fmt, flags);
975  SDL_FreeFormat(fmt);
976  }
977  return convert;
978 }
979 
980 /*
981  * Create a surface on the stack for quick blit operations
982  */
983 static SDL_INLINE SDL_bool
985  void * pixels, int pitch, SDL_Surface * surface,
986  SDL_PixelFormat * format, SDL_BlitMap * blitmap)
987 {
988  if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
989  SDL_SetError("Indexed pixel formats not supported");
990  return SDL_FALSE;
991  }
992  if (SDL_InitFormat(format, pixel_format) < 0) {
993  return SDL_FALSE;
994  }
995 
996  SDL_zerop(surface);
997  surface->flags = SDL_PREALLOC;
998  surface->format = format;
999  surface->pixels = pixels;
1000  surface->w = width;
1001  surface->h = height;
1002  surface->pitch = pitch;
1003  /* We don't actually need to set up the clip rect for our purposes */
1004  /* SDL_SetClipRect(surface, NULL); */
1005 
1006  /* Allocate an empty mapping */
1007  SDL_zerop(blitmap);
1008  blitmap->info.r = 0xFF;
1009  blitmap->info.g = 0xFF;
1010  blitmap->info.b = 0xFF;
1011  blitmap->info.a = 0xFF;
1012  surface->map = blitmap;
1013 
1014  /* The surface is ready to go */
1015  surface->refcount = 1;
1016  return SDL_TRUE;
1017 }
1018 
1019 /*
1020  * Copy a block of pixels of one format to another format
1021  */
1023  Uint32 src_format, const void * src, int src_pitch,
1024  Uint32 dst_format, void * dst, int dst_pitch)
1025 {
1026  SDL_Surface src_surface, dst_surface;
1027  SDL_PixelFormat src_fmt, dst_fmt;
1028  SDL_BlitMap src_blitmap, dst_blitmap;
1029  SDL_Rect rect;
1030  void *nonconst_src = (void *) src;
1031 
1032  /* Check to make sure we are blitting somewhere, so we don't crash */
1033  if (!dst) {
1034  return SDL_InvalidParamError("dst");
1035  }
1036  if (!dst_pitch) {
1037  return SDL_InvalidParamError("dst_pitch");
1038  }
1039 
1040  /* Fast path for same format copy */
1041  if (src_format == dst_format) {
1042  int bpp, i;
1043 
1044  if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
1045  switch (src_format) {
1046  case SDL_PIXELFORMAT_YUY2:
1047  case SDL_PIXELFORMAT_UYVY:
1048  case SDL_PIXELFORMAT_YVYU:
1049  bpp = 2;
1050  break;
1051  case SDL_PIXELFORMAT_YV12:
1052  case SDL_PIXELFORMAT_IYUV:
1053  case SDL_PIXELFORMAT_NV12:
1054  case SDL_PIXELFORMAT_NV21:
1055  bpp = 1;
1056  break;
1057  default:
1058  return SDL_SetError("Unknown FOURCC pixel format");
1059  }
1060  } else {
1061  bpp = SDL_BYTESPERPIXEL(src_format);
1062  }
1063  width *= bpp;
1064 
1065  for (i = height; i--;) {
1066  SDL_memcpy(dst, src, width);
1067  src = (Uint8*)src + src_pitch;
1068  dst = (Uint8*)dst + dst_pitch;
1069  }
1070 
1071  if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) {
1072  /* U and V planes are a quarter the size of the Y plane */
1073  width /= 2;
1074  height /= 2;
1075  src_pitch /= 2;
1076  dst_pitch /= 2;
1077  for (i = height * 2; i--;) {
1078  SDL_memcpy(dst, src, width);
1079  src = (Uint8*)src + src_pitch;
1080  dst = (Uint8*)dst + dst_pitch;
1081  }
1082  } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) {
1083  /* U/V plane is half the height of the Y plane */
1084  height /= 2;
1085  for (i = height; i--;) {
1086  SDL_memcpy(dst, src, width);
1087  src = (Uint8*)src + src_pitch;
1088  dst = (Uint8*)dst + dst_pitch;
1089  }
1090  }
1091  return 0;
1092  }
1093 
1094  if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
1095  src_pitch,
1096  &src_surface, &src_fmt, &src_blitmap)) {
1097  return -1;
1098  }
1099  if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
1100  &dst_surface, &dst_fmt, &dst_blitmap)) {
1101  return -1;
1102  }
1103 
1104  /* Set up the rect and go! */
1105  rect.x = 0;
1106  rect.y = 0;
1107  rect.w = width;
1108  rect.h = height;
1109  return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
1110 }
1111 
1112 /*
1113  * Free a surface created by the above function.
1114  */
1115 void
1117 {
1118  if (surface == NULL) {
1119  return;
1120  }
1121  if (surface->flags & SDL_DONTFREE) {
1122  return;
1123  }
1124  if (--surface->refcount > 0) {
1125  return;
1126  }
1127  while (surface->locked > 0) {
1128  SDL_UnlockSurface(surface);
1129  }
1130  if (surface->flags & SDL_RLEACCEL) {
1131  SDL_UnRLESurface(surface, 0);
1132  }
1133  if (surface->format) {
1134  SDL_SetSurfacePalette(surface, NULL);
1135  SDL_FreeFormat(surface->format);
1136  surface->format = NULL;
1137  }
1138  if (surface->map != NULL) {
1139  SDL_FreeBlitMap(surface->map);
1140  surface->map = NULL;
1141  }
1142  if (!(surface->flags & SDL_PREALLOC)) {
1143  SDL_free(surface->pixels);
1144  }
1145  SDL_free(surface);
1146 }
1147 
1148 /* vi: set ts=4 sw=4 expandtab: */
int SDL_GetColorKey(SDL_Surface *surface, Uint32 *key)
Gets the color key (transparent pixel) in a blittable surface.
Definition: SDL_surface.c:222
GLenum GLenum dst
Uint8 r
Definition: SDL_blit.h:70
#define SDL_COPY_MODULATE_COLOR
Definition: SDL_blit.h:34
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1565
void SDL_UnlockSurface(SDL_Surface *surface)
Definition: SDL_surface.c:824
Uint32 version
Definition: SDL_pixels.h:292
Uint8 b
Definition: SDL_blit.h:70
SDL_bool SDL_SetClipRect(SDL_Surface *surface, const SDL_Rect *rect)
Definition: SDL_surface.c:457
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2072
#define SDL_COPY_COLORKEY
Definition: SDL_blit.h:39
GLint GLint GLsizei width
Definition: SDL_opengl.h:1565
SDL_blit blit
Definition: SDL_blit.h:89
int SDL_SetSurfaceRLE(SDL_Surface *surface, int flag)
Sets the RLE acceleration hint for a surface.
Definition: SDL_surface.c:156
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
Uint8 g
Definition: SDL_pixels.h:282
#define SDL_MapRGBA
#define SDL_SoftStretch
#define SDL_ISPIXELFORMAT_INDEXED(format)
Definition: SDL_pixels.h:133
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
int SDL_LockSurface(SDL_Surface *surface)
Sets up a surface for directly accessing the pixels.
Definition: SDL_surface.c:803
SDL_Surface * SDL_ConvertSurfaceFormat(SDL_Surface *surface, Uint32 pixel_format, Uint32 flags)
Definition: SDL_surface.c:966
SDL_BlendMode
The blend mode used in SDL_RenderCopy() and drawing operations.
Definition: SDL_blendmode.h:40
Uint8 BytesPerPixel
Definition: SDL_pixels.h:304
SDL_Rect rect
Definition: testrelative.c:27
Uint8 g
Definition: SDL_blit.h:70
#define SDL_MasksToPixelFormatEnum
SDL_Surface * SDL_ConvertSurface(SDL_Surface *surface, const SDL_PixelFormat *format, Uint32 flags)
Definition: SDL_surface.c:842
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)
Definition: SDL_surface.c:984
#define SDL_COPY_MOD
Definition: SDL_blit.h:38
int SDL_SetSurfaceColorMod(SDL_Surface *surface, Uint8 r, Uint8 g, Uint8 b)
Set an additional color value used in blit operations.
Definition: SDL_surface.c:310
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
int SDL_SetSurfaceAlphaMod(SDL_Surface *surface, Uint8 alpha)
Set an additional alpha value used in blit operations.
Definition: SDL_surface.c:355
#define SDL_DONTFREE
Definition: SDL_surface.h:55
int SDL_UpperBlitScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
Definition: SDL_surface.c:622
int SDL_SetSurfaceBlendMode(SDL_Surface *surface, SDL_BlendMode blendMode)
Set the blend mode used for blit operations.
Definition: SDL_surface.c:391
void SDL_UnRLESurface(SDL_Surface *surface, int recode)
#define SDL_BlitSurface
Definition: SDL_surface.h:447
static void SDL_ConvertColorkeyToAlpha(SDL_Surface *surface)
Definition: SDL_surface.c:240
#define SDL_BYTESPERPIXEL(X)
Definition: SDL_pixels.h:127
Uint32 dst_palette_version
Definition: SDL_blit.h:95
Uint8 b
Definition: SDL_pixels.h:283
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: SDL_opengl.h:1565
#define SDL_AllocFormat
#define SDL_COPY_RLE_COLORKEY
Definition: SDL_blit.h:42
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1565
#define SDL_IntersectRect
#define SDL_floor
int SDL_LowerBlit(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
Definition: SDL_surface.c:500
#define SDL_zerop(x)
Definition: SDL_stdinc.h:356
int SDL_SetColorKey(SDL_Surface *surface, int flag, Uint32 key)
Sets the color key (transparent pixel) in a blittable surface.
Definition: SDL_surface.c:177
int SDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
Definition: SDL_surface.c:523
GLfloat GLfloat GLfloat alpha
#define SDL_COPY_ADD
Definition: SDL_blit.h:37
Uint32 colorkey
Definition: SDL_blit.h:69
Uint32 flags
Definition: SDL_surface.h:71
void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect)
Definition: SDL_surface.c:481
Uint32 src_palette_version
Definition: SDL_blit.h:96
#define SDL_COPY_RLE_DESIRED
Definition: SDL_blit.h:41
static SDL_BlendMode blendMode
Definition: testdraw2.c:34
SDL_bool
Definition: SDL_stdinc.h:126
void SDL_InvalidateMap(SDL_BlitMap *map)
Definition: SDL_pixels.c:974
GLboolean GLboolean g
#define SDL_COPY_NEAREST
Definition: SDL_blit.h:40
#define SDL_ALPHA_TRANSPARENT
Definition: SDL_pixels.h:46
struct SDL_BlitMap * map
Definition: SDL_surface.h:88
#define SDL_memcpy
void * SDL_calloc(size_t nmemb, size_t size)
Uint8 r
Definition: SDL_pixels.h:281
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
int SDL_MapSurface(SDL_Surface *src, SDL_Surface *dst)
Definition: SDL_pixels.c:993
void * pixels
Definition: SDL_surface.h:75
Uint8 a
Definition: SDL_pixels.h:284
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
Uint8 BitsPerPixel
Definition: SDL_pixels.h:303
int SDL_SetSurfacePalette(SDL_Surface *surface, SDL_Palette *palette)
Set the palette used by a surface.
Definition: SDL_surface.c:142
void SDL_free(void *mem)
int SDL_GetSurfaceBlendMode(SDL_Surface *surface, SDL_BlendMode *blendMode)
Get the blend mode used for blit operations.
Definition: SDL_surface.c:428
int SDL_ConvertPixels(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch)
Copy a block of pixels of one format to another format.
Definition: SDL_surface.c:1022
#define SDL_FreeFormat
#define SDL_memcmp
int SDL_GetSurfaceAlphaMod(SDL_Surface *surface, Uint8 *alpha)
Get the additional alpha value used in blit operations.
Definition: SDL_surface.c:378
int x
Definition: SDL_rect.h:66
int w
Definition: SDL_rect.h:67
GLenum GLint GLuint mask
#define SDL_GetRGBA
#define SDL_AllocPalette
int SDL_InitFormat(SDL_PixelFormat *format, Uint32 pixel_format)
Definition: SDL_pixels.c:521
SDL_Rect clip_rect
Definition: SDL_surface.h:85
void SDL_FreeSurface(SDL_Surface *surface)
Definition: SDL_surface.c:1116
int SDL_RLESurface(SDL_Surface *surface)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
SDL_Surface * dst
Definition: SDL_blit.h:87
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_Color * colors
Definition: SDL_pixels.h:291
SDL_PixelFormat * format
Definition: SDL_surface.h:72
GLint GLint GLsizei GLsizei GLsizei depth
Definition: SDL_opengl.h:1565
#define SDL_FreePalette
#define SDL_SetError
SDL_Surface * SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
Definition: SDL_surface.c:34
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define SDL_COPY_MODULATE_ALPHA
Definition: SDL_blit.h:35
int h
Definition: SDL_rect.h:67
#define SDL_COPY_RLE_ALPHAKEY
Definition: SDL_blit.h:43
int SDL_LowerBlitScaled(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
Definition: SDL_surface.c:776
SDL_BlitMap * SDL_AllocBlitMap(void)
Definition: SDL_pixels.c:954
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:147
Uint32 pixel_format
Definition: testoverlay2.c:152
GLbitfield flags
#define SDL_INLINE
Definition: begin_code.h:120
int SDL_CalculatePitch(SDL_Surface *surface)
Definition: SDL_pixels.c:748
#define SDL_malloc
GLubyte GLubyte GLubyte GLubyte w
SDL_Palette * palette
Definition: SDL_pixels.h:302
#define SDL_ISPIXELFORMAT_FOURCC(format)
Definition: SDL_pixels.h:166
SDL_Surface * SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
Definition: SDL_surface.c:121
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:45
GLenum src
GLboolean GLboolean GLboolean b
void SDL_FreeBlitMap(SDL_BlitMap *map)
Definition: SDL_pixels.c:1079
int SDL_GetSurfaceColorMod(SDL_Surface *surface, Uint8 *r, Uint8 *g, Uint8 *b)
Get the additional color value used in blit operations.
Definition: SDL_surface.c:336
GLenum GLenum void * row
int y
Definition: SDL_rect.h:66
#define SDL_SetPixelFormatPalette
#define SDL_Unsupported()
Definition: SDL_error.h:53
GLfloat GLfloat GLfloat GLfloat h
#define SDL_COPY_BLEND
Definition: SDL_blit.h:36
SDL_BlitInfo info
Definition: SDL_blit.h:91
#define SDL_memset
#define SDL_PREALLOC
Definition: SDL_surface.h:53
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
#define SDL_RLEACCEL
Definition: SDL_surface.h:54
Uint8 a
Definition: SDL_blit.h:70