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