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