1 /*
2 pygame - Python Game Library
3 Copyright (C) 2000-2001 Pete Shinners
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Pete Shinners
20 pete@shinners.org
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <fc_config.h>
25 #endif
26
27 /* SDL */
28 #include <SDL/SDL.h>
29
30 /* utility.h */
31 #include "shared.h"
32
33 int pygame_AlphaBlit (SDL_Surface *src, SDL_Rect *srcrect,
34 SDL_Surface *dst, SDL_Rect *dstrect);
35
36 /* The structure passed to the low level blit functions */
37 typedef struct {
38 Uint8 *s_pixels;
39 int s_width;
40 int s_height;
41 int s_skip;
42 Uint8 *d_pixels;
43 int d_width;
44 int d_height;
45 int d_skip;
46 void *aux_data;
47 SDL_PixelFormat *src;
48 Uint8 *table;
49 SDL_PixelFormat *dst;
50 } SDL_BlitInfo;
51 static void alphablit_alpha(SDL_BlitInfo *info);
52 static void alphablit_colorkey(SDL_BlitInfo *info);
53 static void alphablit_solid(SDL_BlitInfo *info);
54 static int SoftBlitAlpha(SDL_Surface *src, SDL_Rect *srcrect,
55 SDL_Surface *dst, SDL_Rect *dstrect);
56 extern int SDL_RLESurface(SDL_Surface *surface);
57 extern void SDL_UnRLESurface(SDL_Surface *surface, int recode);
58
59
60 /**********************************************************************
61 Blit from source rectangle to destination rectangle with alpha.
62 If dstrect is NULL, full dst surface is used.
63 We assume the "dst" has pixel alpha.
64 ***********************************************************************/
pygame_AlphaBlit(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)65 int pygame_AlphaBlit (SDL_Surface *src, SDL_Rect *srcrect,
66 SDL_Surface *dst, SDL_Rect *dstrect)
67 {
68 SDL_Rect fulldst;
69 int srcx, srcy, w, h;
70
71 /* Make sure the surfaces aren't locked */
72 if ( ! src || ! dst ) {
73 SDL_SetError("SDL_UpperBlit: passed a NULL surface");
74 return(-1);
75 }
76 if ( src->locked || dst->locked ) {
77 SDL_SetError("Surfaces must not be locked during blit");
78 return(-1);
79 }
80
81 /* If the destination rectangle is NULL, use the entire dest surface */
82 if ( dstrect == NULL ) {
83 fulldst.x = fulldst.y = 0;
84 dstrect = &fulldst;
85 }
86
87 /* clip the source rectangle to the source surface */
88 if(srcrect) {
89 int maxw, maxh;
90
91 srcx = srcrect->x;
92 w = srcrect->w;
93 if(srcx < 0) {
94 w += srcx;
95 dstrect->x -= srcx;
96 srcx = 0;
97 }
98 maxw = src->w - srcx;
99 if(maxw < w)
100 w = maxw;
101
102 srcy = srcrect->y;
103 h = srcrect->h;
104 if(srcy < 0) {
105 h += srcy;
106 dstrect->y -= srcy;
107 srcy = 0;
108 }
109 maxh = src->h - srcy;
110 if(maxh < h)
111 h = maxh;
112
113 } else {
114 srcx = srcy = 0;
115 w = src->w;
116 h = src->h;
117 }
118
119 /* clip the destination rectangle against the clip rectangle */
120 {
121 SDL_Rect *clip = &dst->clip_rect;
122 int dx, dy;
123
124 dx = clip->x - dstrect->x;
125 if(dx > 0) {
126 w -= dx;
127 dstrect->x += dx;
128 srcx += dx;
129 }
130 dx = dstrect->x + w - clip->x - clip->w;
131 if(dx > 0)
132 w -= dx;
133
134 dy = clip->y - dstrect->y;
135 if(dy > 0) {
136 h -= dy;
137 dstrect->y += dy;
138 srcy += dy;
139 }
140 dy = dstrect->y + h - clip->y - clip->h;
141 if(dy > 0)
142 h -= dy;
143 }
144
145 if(w > 0 && h > 0) {
146 SDL_Rect sr;
147 sr.x = srcx;
148 sr.y = srcy;
149 sr.w = dstrect->w = w;
150 sr.h = dstrect->h = h;
151 return SoftBlitAlpha(src, &sr, dst, dstrect);
152 }
153 dstrect->w = dstrect->h = 0;
154 return 0;
155 }
156
157 /**********************************************************************
158 Blit using alpha from src to dest. Rectangles are assumed to be
159 already clipped.
160 ***********************************************************************/
SoftBlitAlpha(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)161 static int SoftBlitAlpha(SDL_Surface *src, SDL_Rect *srcrect,
162 SDL_Surface *dst, SDL_Rect *dstrect)
163 {
164 int okay;
165 int src_locked;
166 int dst_locked;
167
168 /* Everything is okay at the beginning... */
169 okay = 1;
170
171 /* Lock the destination if it's in hardware */
172 dst_locked = 0;
173 if ( SDL_MUSTLOCK(dst) ) {
174 if ( SDL_LockSurface(dst) < 0 )
175 okay = 0;
176 else
177 dst_locked = 1;
178 }
179 /* Lock the source if it's in hardware */
180 src_locked = 0;
181 if ( SDL_MUSTLOCK(src) ) {
182 if ( SDL_LockSurface(src) < 0 )
183 okay = 0;
184 else
185 src_locked = 1;
186 }
187
188 /* Set up source and destination buffer pointers, and BLIT! */
189 if ( okay && srcrect->w && srcrect->h ) {
190 SDL_BlitInfo info;
191
192 /* Set up the blit information */
193 info.s_pixels = (Uint8 *)src->pixels + src->offset +
194 (Uint16)srcrect->y*src->pitch +
195 (Uint16)srcrect->x*src->format->BytesPerPixel;
196 info.s_width = srcrect->w;
197 info.s_height = srcrect->h;
198 info.s_skip=src->pitch-info.s_width*src->format->BytesPerPixel;
199 info.d_pixels = (Uint8 *)dst->pixels + dst->offset +
200 (Uint16)dstrect->y*dst->pitch +
201 (Uint16)dstrect->x*dst->format->BytesPerPixel;
202 info.d_width = dstrect->w;
203 info.d_height = dstrect->h;
204 info.d_skip=dst->pitch-info.d_width*dst->format->BytesPerPixel;
205 info.src = src->format;
206 info.dst = dst->format;
207
208 if(src->flags&SDL_SRCALPHA && src->format->Amask)
209 alphablit_alpha(&info);
210 else if(src->flags & SDL_SRCCOLORKEY)
211 alphablit_colorkey(&info);
212 else
213 alphablit_solid(&info);
214 }
215
216 /* We need to unlock the surfaces if they're locked */
217 if ( dst_locked )
218 SDL_UnlockSurface(dst);
219 if ( src_locked )
220 SDL_UnlockSurface(src);
221 /* Blit is done! */
222 return(okay ? 0 : -1);
223 }
224
225
226 #define GET_PIXEL(buf, bpp, fmt, pixel) \
227 do { \
228 switch (bpp) { \
229 case 1: \
230 pixel = *((Uint8 *)(buf)); \
231 break; \
232 case 2: \
233 pixel = *((Uint16 *)(buf)); \
234 break; \
235 case 4: \
236 pixel = *((Uint32 *)(buf)); \
237 break; \
238 default: {/* case 3: FIXME: broken code (no alpha) */ \
239 Uint8 *b = (Uint8 *)buf; \
240 if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
241 pixel = b[0] + (b[1] << 8) + (b[2] << 16); \
242 } else { \
243 pixel = (b[0] << 16) + (b[1] << 8) + b[2]; \
244 } \
245 } \
246 break; \
247 } \
248 } while(0)
249
250
251 #define DISEMBLE_RGB(buf, bpp, fmt, pixel, R, G, B) \
252 do { \
253 Uint8 *b = (Uint8 *)buf; \
254 if (bpp == 1) { \
255 pixel = *((Uint8 *)(buf)); \
256 R = fmt->palette->colors[pixel].r; \
257 G = fmt->palette->colors[pixel].g; \
258 B = fmt->palette->colors[pixel].b; \
259 } else { \
260 switch (bpp) { \
261 case 2: \
262 if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
263 pixel = b[0] + (b[1] << 8); \
264 } else { \
265 pixel = (b[0] << 8) + b[1]; \
266 } \
267 break; \
268 case 4: \
269 if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
270 pixel = b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); \
271 } else { \
272 pixel = (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3]; \
273 } \
274 break; \
275 default: \
276 { /* case 3: FIXME: broken code (no alpha) */ \
277 if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
278 pixel = b[0] + (b[1] << 8) + (b[2] << 16); \
279 } else { \
280 pixel = (b[0] << 16) + (b[1] << 8) + b[2]; \
281 } \
282 } \
283 break; \
284 } \
285 R = ((pixel & fmt->Rmask) >> fmt->Rshift) << fmt->Rloss; \
286 G = ((pixel & fmt->Gmask) >> fmt->Gshift) << fmt->Gloss; \
287 B = ((pixel & fmt->Bmask) >> fmt->Bshift) << fmt->Bloss; \
288 } \
289 } while(FALSE);
290
291 #define DISEMBLE_RGBA(buf, bpp, fmt, pixel, R, G, B, A) \
292 do { \
293 DISEMBLE_RGB(buf, bpp, fmt, pixel, R, G, B); \
294 if (bpp == 1) { \
295 A = 255; \
296 } else { \
297 A = ((pixel & fmt->Amask) >> fmt->Ashift) << fmt->Aloss; \
298 } \
299 } while(FALSE);
300
301 #define PIXEL_FROM_RGBA(pixel, fmt, r, g, b, a) \
302 { \
303 pixel = ((r >> fmt->Rloss) << fmt->Rshift) | \
304 ((g >> fmt->Gloss) << fmt->Gshift) | \
305 ((b >> fmt->Bloss) << fmt->Bshift) | \
306 ((a << fmt->Aloss) << fmt->Ashift); \
307 }
308
309 #define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a) \
310 { \
311 switch (bpp) { \
312 case 2: \
313 { \
314 Uint16 pxl; \
315 PIXEL_FROM_RGBA(pxl, fmt, r, g, b, a); \
316 if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
317 buf[0] = (pxl & 0x00ff); \
318 buf[1] = (pxl & 0xff00) >> 8; \
319 } else { \
320 buf[0] = (pxl & 0xff00) >> 8; \
321 buf[1] = (pxl & 0x00ff); \
322 } \
323 } \
324 break; \
325 case 4: \
326 { \
327 Uint32 pxl; \
328 PIXEL_FROM_RGBA(pxl, fmt, r, g, b, a); \
329 if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
330 buf[0] = (pxl & 0x000000ff); \
331 buf[1] = (pxl & 0x0000ff00) >> 8; \
332 buf[2] = (pxl & 0x00ff0000) >> 16; \
333 buf[3] = (pxl & 0xff000000) >> 24; \
334 } else { \
335 buf[3] = (pxl & 0x000000ff); \
336 buf[2] = (pxl & 0x0000ff00) >> 8; \
337 buf[1] = (pxl & 0x00ff0000) >> 16; \
338 buf[0] = (pxl & 0xff000000) >> 24; \
339 } \
340 } \
341 break; \
342 } \
343 }
344
345 #if 0
346 #define ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB, dA) \
347 do { \
348 dR = (((sR-dR)*(sA))>>8)+dR; \
349 dG = (((sG-dG)*(sA))>>8)+dG; \
350 dB = (((sB-dB)*(sA))>>8)+dB; \
351 dA = sA+dA - ((sA*dA)/255); \
352 } while(0)
353 #else /* 0 */
354 #define ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB, dA) \
355 do { if(dA){\
356 dR = ( ((255-sA)*dR ) + ((sR*sA)) ) >> 8; \
357 dG = ( ((255-sA)*dG ) + ((sG*sA)) ) >> 8; \
358 dB = ( ((255-sA)*dB ) + ((sB*sA)) ) >> 8; \
359 dA = sA+dA - ((sA*dA)/255); \
360 }else{\
361 dR = sR; \
362 dG = sG; \
363 dB = sB; \
364 dA = sA; \
365 }\
366 } while(0)
367 #endif /* !0 */
368
369 #if 0
370 /* a sad tale of many other blending techniques that didn't fly */
371 if(0&&dA){\
372 dR = (((255-sA)*(dR<<8)/dA)) + (sR>>8) ) >> 8; \
373 dG = (((255-sA)*(dG<<8)/dA)) + (sG>>8) ) >> 8; \
374 dB = (((255-sA)*(dB<<8)/dA)) + (sB>>8) ) >> 8; \
375 dA = sA+dA - ((sA*dA)>>8); \
376 }else{\
377 dR = 255; \
378 dG = 0; \
379 dB = 255; \
380 dA = 255; \
381 }\
382
383
384 int temp; \
385 temp = (((sR-dR)*(sA))>>8)+dR; dR = (((sR-temp)*(255-dA))>>8)+temp; \
386 temp = (((sG-dG)*(sA))>>8)+dG; dG = (((sG-temp)*(255-dA))>>8)+temp; \
387 temp = (((sB-dB)*(sA))>>8)+dB; dB = (((sB-temp)*(255-dA))>>8)+temp; \
388
389 temp = (((sR-dR)*(sA))>>8)+dR; dR = (((temp-sR)*dA)>>8)+sR; \
390 temp = (((sG-dG)*(sA))>>8)+dG; dG = (((temp-sG)*dA)>>8)+sG; \
391 temp = (((sB-dB)*(sA))>>8)+dB; dB = (((temp-sB)*dA)>>8)+sB; \
392
393 dR = (((dR - sR) * (255-sA) * dA) >> 16) + (sR*sA)>>8);
394 dG = (((dG - sG) * (255-sA) * dA) >> 16) + (sG*sA)>>8);
395 dB = (((dB - sB) * (255-sA) * dA) >> 16) + (sB*sA)>>8);
396 #endif /* 0 */
397
398
399 /**********************************************************************
400 Basic alpha blitting
401 ***********************************************************************/
alphablit_alpha(SDL_BlitInfo * info)402 static void alphablit_alpha(SDL_BlitInfo *info)
403 {
404 int n;
405 int width = info->d_width;
406 int height = info->d_height;
407 Uint8 *src = info->s_pixels;
408 int srcskip = info->s_skip;
409 Uint8 *dst = info->d_pixels;
410 int dstskip = info->d_skip;
411 SDL_PixelFormat *srcfmt = info->src;
412 SDL_PixelFormat *dstfmt = info->dst;
413 int srcbpp = srcfmt->BytesPerPixel;
414 int dstbpp = dstfmt->BytesPerPixel;
415 int dR, dG, dB, dA, sR, sG, sB, sA;
416
417 while ( height-- )
418 {
419 for(n=width; n>0; --n)
420 {
421 Uint32 pixel;
422 DISEMBLE_RGBA(src, srcbpp, srcfmt, pixel, sR, sG, sB, sA);
423 DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
424 ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB, dA);
425 ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
426 src += srcbpp;
427 dst += dstbpp;
428 }
429 src += srcskip;
430 dst += dstskip;
431 }
432 }
433
434 /**********************************************************************
435 Blit using colorkey
436 ***********************************************************************/
alphablit_colorkey(SDL_BlitInfo * info)437 static void alphablit_colorkey(SDL_BlitInfo *info)
438 {
439 int n;
440 int width = info->d_width;
441 int height = info->d_height;
442 Uint8 *src = info->s_pixels;
443 int srcskip = info->s_skip;
444 Uint8 *dst = info->d_pixels;
445 int dstskip = info->d_skip;
446 SDL_PixelFormat *srcfmt = info->src;
447 SDL_PixelFormat *dstfmt = info->dst;
448 int srcbpp = srcfmt->BytesPerPixel;
449 int dstbpp = dstfmt->BytesPerPixel;
450 int dR, dG, dB, dA, sR, sG, sB, sA;
451 int alpha = srcfmt->alpha;
452 Uint32 colorkey = srcfmt->colorkey;
453
454 while ( height-- )
455 {
456 for(n=width; n>0; --n)
457 {
458 Uint32 pixel;
459 DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
460 DISEMBLE_RGBA(src, srcbpp, srcfmt, pixel, sR, sG, sB, sA);
461 sA = (pixel == colorkey) ? 0 : alpha;
462 ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB, dA);
463 ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
464 src += srcbpp;
465 dst += dstbpp;
466 }
467 src += srcskip;
468 dst += dstskip;
469 }
470 }
471
472 /**********************************************************************
473 Blit solid surface
474 ***********************************************************************/
alphablit_solid(SDL_BlitInfo * info)475 static void alphablit_solid(SDL_BlitInfo *info)
476 {
477 int n;
478 int width = info->d_width;
479 int height = info->d_height;
480 Uint8 *src = info->s_pixels;
481 int srcskip = info->s_skip;
482 Uint8 *dst = info->d_pixels;
483 int dstskip = info->d_skip;
484 SDL_PixelFormat *srcfmt = info->src;
485 SDL_PixelFormat *dstfmt = info->dst;
486 int srcbpp = srcfmt->BytesPerPixel;
487 int dstbpp = dstfmt->BytesPerPixel;
488 int dR, dG, dB, dA, sR, sG, sB;
489 int alpha = srcfmt->alpha;
490
491 while ( height-- )
492 {
493 for(n=width; n>0; --n)
494 {
495 int pixel;
496 DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
497 DISEMBLE_RGB(src, srcbpp, srcfmt, pixel, sR, sG, sB);
498 ALPHA_BLEND(sR, sG, sB, alpha, dR, dG, dB, dA);
499 ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
500 src += srcbpp;
501 dst += dstbpp;
502 }
503 src += srcskip;
504 dst += dstskip;
505 }
506 }
507