1 /*
2
3 SDL_gfxBlitFunc.c: custom blitters
4
5 Copyright (C) 2001-2012 Andreas Schiffler
6
7 This software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any damages
9 arising from the use of this software.
10
11 Permission is granted to anyone to use this software for any purpose,
12 including commercial applications, and to alter it and redistribute it
13 freely, subject to the following restrictions:
14
15 1. The origin of this software must not be misrepresented; you must not
16 claim that you wrote the original software. If you use this software
17 in a product, an acknowledgment in the product documentation would be
18 appreciated but is not required.
19
20 2. Altered source versions must be plainly marked as such, and must not be
21 misrepresented as being the original software.
22
23 3. This notice may not be removed or altered from any source
24 distribution.
25
26 Andreas Schiffler -- aschiffler at ferzkopp dot net
27
28 */
29
30 #include "SDL_gfxBlitFunc.h"
31
32 /*!
33 \brief Alpha adjustment table for custom blitter.
34
35 The table provides values for a modified, non-linear
36 transfer function which maintain brightness.
37
38 */
39 const unsigned int GFX_ALPHA_ADJUST_ARRAY[256] = {
40 0, /* 0 */
41 15, /* 1 */
42 22, /* 2 */
43 27, /* 3 */
44 31, /* 4 */
45 35, /* 5 */
46 39, /* 6 */
47 42, /* 7 */
48 45, /* 8 */
49 47, /* 9 */
50 50, /* 10 */
51 52, /* 11 */
52 55, /* 12 */
53 57, /* 13 */
54 59, /* 14 */
55 61, /* 15 */
56 63, /* 16 */
57 65, /* 17 */
58 67, /* 18 */
59 69, /* 19 */
60 71, /* 20 */
61 73, /* 21 */
62 74, /* 22 */
63 76, /* 23 */
64 78, /* 24 */
65 79, /* 25 */
66 81, /* 26 */
67 82, /* 27 */
68 84, /* 28 */
69 85, /* 29 */
70 87, /* 30 */
71 88, /* 31 */
72 90, /* 32 */
73 91, /* 33 */
74 93, /* 34 */
75 94, /* 35 */
76 95, /* 36 */
77 97, /* 37 */
78 98, /* 38 */
79 99, /* 39 */
80 100, /* 40 */
81 102, /* 41 */
82 103, /* 42 */
83 104, /* 43 */
84 105, /* 44 */
85 107, /* 45 */
86 108, /* 46 */
87 109, /* 47 */
88 110, /* 48 */
89 111, /* 49 */
90 112, /* 50 */
91 114, /* 51 */
92 115, /* 52 */
93 116, /* 53 */
94 117, /* 54 */
95 118, /* 55 */
96 119, /* 56 */
97 120, /* 57 */
98 121, /* 58 */
99 122, /* 59 */
100 123, /* 60 */
101 124, /* 61 */
102 125, /* 62 */
103 126, /* 63 */
104 127, /* 64 */
105 128, /* 65 */
106 129, /* 66 */
107 130, /* 67 */
108 131, /* 68 */
109 132, /* 69 */
110 133, /* 70 */
111 134, /* 71 */
112 135, /* 72 */
113 136, /* 73 */
114 137, /* 74 */
115 138, /* 75 */
116 139, /* 76 */
117 140, /* 77 */
118 141, /* 78 */
119 141, /* 79 */
120 142, /* 80 */
121 143, /* 81 */
122 144, /* 82 */
123 145, /* 83 */
124 146, /* 84 */
125 147, /* 85 */
126 148, /* 86 */
127 148, /* 87 */
128 149, /* 88 */
129 150, /* 89 */
130 151, /* 90 */
131 152, /* 91 */
132 153, /* 92 */
133 153, /* 93 */
134 154, /* 94 */
135 155, /* 95 */
136 156, /* 96 */
137 157, /* 97 */
138 158, /* 98 */
139 158, /* 99 */
140 159, /* 100 */
141 160, /* 101 */
142 161, /* 102 */
143 162, /* 103 */
144 162, /* 104 */
145 163, /* 105 */
146 164, /* 106 */
147 165, /* 107 */
148 165, /* 108 */
149 166, /* 109 */
150 167, /* 110 */
151 168, /* 111 */
152 168, /* 112 */
153 169, /* 113 */
154 170, /* 114 */
155 171, /* 115 */
156 171, /* 116 */
157 172, /* 117 */
158 173, /* 118 */
159 174, /* 119 */
160 174, /* 120 */
161 175, /* 121 */
162 176, /* 122 */
163 177, /* 123 */
164 177, /* 124 */
165 178, /* 125 */
166 179, /* 126 */
167 179, /* 127 */
168 180, /* 128 */
169 181, /* 129 */
170 182, /* 130 */
171 182, /* 131 */
172 183, /* 132 */
173 184, /* 133 */
174 184, /* 134 */
175 185, /* 135 */
176 186, /* 136 */
177 186, /* 137 */
178 187, /* 138 */
179 188, /* 139 */
180 188, /* 140 */
181 189, /* 141 */
182 190, /* 142 */
183 190, /* 143 */
184 191, /* 144 */
185 192, /* 145 */
186 192, /* 146 */
187 193, /* 147 */
188 194, /* 148 */
189 194, /* 149 */
190 195, /* 150 */
191 196, /* 151 */
192 196, /* 152 */
193 197, /* 153 */
194 198, /* 154 */
195 198, /* 155 */
196 199, /* 156 */
197 200, /* 157 */
198 200, /* 158 */
199 201, /* 159 */
200 201, /* 160 */
201 202, /* 161 */
202 203, /* 162 */
203 203, /* 163 */
204 204, /* 164 */
205 205, /* 165 */
206 205, /* 166 */
207 206, /* 167 */
208 206, /* 168 */
209 207, /* 169 */
210 208, /* 170 */
211 208, /* 171 */
212 209, /* 172 */
213 210, /* 173 */
214 210, /* 174 */
215 211, /* 175 */
216 211, /* 176 */
217 212, /* 177 */
218 213, /* 178 */
219 213, /* 179 */
220 214, /* 180 */
221 214, /* 181 */
222 215, /* 182 */
223 216, /* 183 */
224 216, /* 184 */
225 217, /* 185 */
226 217, /* 186 */
227 218, /* 187 */
228 218, /* 188 */
229 219, /* 189 */
230 220, /* 190 */
231 220, /* 191 */
232 221, /* 192 */
233 221, /* 193 */
234 222, /* 194 */
235 222, /* 195 */
236 223, /* 196 */
237 224, /* 197 */
238 224, /* 198 */
239 225, /* 199 */
240 225, /* 200 */
241 226, /* 201 */
242 226, /* 202 */
243 227, /* 203 */
244 228, /* 204 */
245 228, /* 205 */
246 229, /* 206 */
247 229, /* 207 */
248 230, /* 208 */
249 230, /* 209 */
250 231, /* 210 */
251 231, /* 211 */
252 232, /* 212 */
253 233, /* 213 */
254 233, /* 214 */
255 234, /* 215 */
256 234, /* 216 */
257 235, /* 217 */
258 235, /* 218 */
259 236, /* 219 */
260 236, /* 220 */
261 237, /* 221 */
262 237, /* 222 */
263 238, /* 223 */
264 238, /* 224 */
265 239, /* 225 */
266 240, /* 226 */
267 240, /* 227 */
268 241, /* 228 */
269 241, /* 229 */
270 242, /* 230 */
271 242, /* 231 */
272 243, /* 232 */
273 243, /* 233 */
274 244, /* 234 */
275 244, /* 235 */
276 245, /* 236 */
277 245, /* 237 */
278 246, /* 238 */
279 246, /* 239 */
280 247, /* 240 */
281 247, /* 241 */
282 248, /* 242 */
283 248, /* 243 */
284 249, /* 244 */
285 249, /* 245 */
286 250, /* 246 */
287 250, /* 247 */
288 251, /* 248 */
289 251, /* 249 */
290 252, /* 250 */
291 252, /* 251 */
292 253, /* 252 */
293 253, /* 253 */
294 254, /* 254 */
295 255 /* 255 */
296 };
297
298 /*!
299 \brief Internal blitter using adjusted destination alpha during RGBA->RGBA blits.
300
301 Performs the blit based on the 'info' structure and applies the transfer function
302 to the destination 'a' values.
303
304 \param info The blit info to use.
305 */
_SDL_gfxBlitBlitterRGBA(SDL_gfxBlitInfo * info)306 void _SDL_gfxBlitBlitterRGBA(SDL_gfxBlitInfo * info)
307 {
308 int width = info->d_width;
309 int height = info->d_height;
310 Uint8 *src = info->s_pixels;
311 int srcskip = info->s_skip;
312 Uint8 *dst = info->d_pixels;
313 int dstskip = info->d_skip;
314 SDL_PixelFormat *srcfmt = info->src;
315 SDL_PixelFormat *dstfmt = info->dst;
316 Uint8 srcbpp = srcfmt->BytesPerPixel;
317 Uint8 dstbpp = dstfmt->BytesPerPixel;
318
319 while (height--) {
320 GFX_DUFFS_LOOP4( {
321 Uint32 pixel;
322 unsigned sR;
323 unsigned sG;
324 unsigned sB;
325 unsigned sA;
326 unsigned dR;
327 unsigned dG;
328 unsigned dB;
329 unsigned dA;
330 unsigned sAA;
331 GFX_DISASSEMBLE_RGBA(src, srcbpp, srcfmt, pixel, sR, sG, sB, sA);
332 GFX_DISASSEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
333 sAA=GFX_ALPHA_ADJUST_ARRAY[sA & 255];
334 GFX_ALPHA_BLEND(sR, sG, sB, sAA, dR, dG, dB);
335 dA |= sAA;
336 GFX_ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
337 src += srcbpp; dst += dstbpp;
338 }, width);
339 src += srcskip;
340 dst += dstskip;
341 }
342 }
343
344 /*!
345 \brief Internal blitter setup wrapper for RGBA->RGBA blits.
346
347 Sets up the blitter info based on the 'src' and 'dst' surfaces and rectangles.
348
349 \param src The source surface.
350 \param srcrect The source rectangle.
351 \param dst The destination surface.
352 \param dstrect The destination rectangle.
353
354 \returns Returns 1 if blit was performed, 0 otherwise.
355 */
_SDL_gfxBlitRGBACall(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)356 int _SDL_gfxBlitRGBACall(SDL_Surface * src, SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect)
357 {
358 /*
359 * Set up source and destination buffer pointers, then blit
360 */
361 if (srcrect->w && srcrect->h) {
362 SDL_gfxBlitInfo info;
363
364 /*
365 * Set up the blit information
366 */
367 #if (SDL_MINOR_VERSION == 3)
368 info.s_pixels = (Uint8 *) src->pixels + (Uint16) srcrect->y * src->pitch + (Uint16) srcrect->x * src->format->BytesPerPixel;
369 #else
370 info.s_pixels = (Uint8 *) src->pixels + src->offset + (Uint16) srcrect->y * src->pitch + (Uint16) srcrect->x * src->format->BytesPerPixel;
371 #endif
372 info.s_width = srcrect->w;
373 info.s_height = srcrect->h;
374 info.s_skip = (int)(src->pitch - info.s_width * src->format->BytesPerPixel);
375 #if (SDL_MINOR_VERSION == 3)
376 info.d_pixels = (Uint8 *) dst->pixels + (Uint16) dstrect->y * dst->pitch + (Uint16) dstrect->x * dst->format->BytesPerPixel;
377 #else
378 info.d_pixels = (Uint8 *) dst->pixels + dst->offset + (Uint16) dstrect->y * dst->pitch + (Uint16) dstrect->x * dst->format->BytesPerPixel;
379 #endif
380 info.d_width = dstrect->w;
381 info.d_height = dstrect->h;
382 info.d_skip = (int)(dst->pitch - info.d_width * dst->format->BytesPerPixel);
383 info.aux_data = NULL;
384 info.src = src->format;
385 info.table = NULL;
386 info.dst = dst->format;
387
388 /*
389 * Run the actual software blitter
390 */
391 _SDL_gfxBlitBlitterRGBA(&info);
392 return 1;
393 }
394
395 return (0);
396 }
397
398 /*!
399 \brief Blitter for RGBA->RGBA blits with alpha adjustment.
400
401 Verifies the input 'src' and 'dst' surfaces and rectangles and performs blit.
402 The destination clip rectangle is honored.
403
404 \param src The source surface.
405 \param srcrect The source rectangle.
406 \param dst The destination surface.
407 \param dstrect The destination rectangle.
408
409 \returns Returns 1 if blit was performed, 0 otherwise, or -1 if an error occured.
410 */
SDL_gfxBlitRGBA(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)411 int SDL_gfxBlitRGBA(SDL_Surface * src, SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect)
412 {
413 SDL_Rect sr, dr;
414 int srcx, srcy, w, h;
415
416 /*
417 * Make sure the surfaces aren't locked
418 */
419 if (!src || !dst) {
420 SDL_SetError("SDL_UpperBlit: passed a NULL surface");
421 return (-1);
422 }
423 if ((src->locked) || (dst->locked)) {
424 SDL_SetError("Surfaces must not be locked during blit");
425 return (-1);
426 }
427
428 /*
429 * If the destination rectangle is NULL, use the entire dest surface
430 */
431 if (dstrect == NULL) {
432 dr.x = dr.y = 0;
433 dr.w = dst->w;
434 dr.h = dst->h;
435 } else {
436 dr = *dstrect;
437 }
438
439 /*
440 * Clip the source rectangle to the source surface
441 */
442 if (srcrect) {
443 int maxw, maxh;
444
445 srcx = srcrect->x;
446 w = srcrect->w;
447 if (srcx < 0) {
448 w += srcx;
449 dr.x -= srcx;
450 srcx = 0;
451 }
452 maxw = src->w - srcx;
453 if (maxw < w)
454 w = maxw;
455
456 srcy = srcrect->y;
457 h = srcrect->h;
458 if (srcy < 0) {
459 h += srcy;
460 dr.y -= srcy;
461 srcy = 0;
462 }
463 maxh = src->h - srcy;
464 if (maxh < h)
465 h = maxh;
466
467 } else {
468 srcx = srcy = 0;
469 w = src->w;
470 h = src->h;
471 }
472
473 /*
474 * Clip the destination rectangle against the clip rectangle
475 */
476 {
477 SDL_Rect *clip = &dst->clip_rect;
478 int dx, dy;
479
480 dx = clip->x - dr.x;
481 if (dx > 0) {
482 w -= dx;
483 dr.x += dx;
484 srcx += dx;
485 }
486 dx = dr.x + w - clip->x - clip->w;
487 if (dx > 0)
488 w -= dx;
489
490 dy = clip->y - dr.y;
491 if (dy > 0) {
492 h -= dy;
493 dr.y += dy;
494 srcy += dy;
495 }
496 dy = dr.y + h - clip->y - clip->h;
497 if (dy > 0)
498 h -= dy;
499 }
500
501 if (w > 0 && h > 0) {
502 sr.x = srcx;
503 sr.y = srcy;
504 sr.w = dr.w = w;
505 sr.h = dr.h = h;
506 return (_SDL_gfxBlitRGBACall(src, &sr, dst, &dr));
507 }
508
509 return 0;
510 }
511
512 /*!
513 \brief Sets the alpha channel in a 32 bit surface.
514
515 Helper function that sets the alpha channel in a 32 bit surface
516 to a constant value.
517 Only 32 bit surfaces can be used with this function.
518
519 \param src Pointer to the target surface to change.
520 \param a The alpha value to set.
521
522 \return Returns 1 if alpha was changed, -1 otherwise.
523 */
SDL_gfxSetAlpha(SDL_Surface * src,Uint8 a)524 int SDL_gfxSetAlpha(SDL_Surface *src, Uint8 a)
525 {
526 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
527 const int alpha_offset = 0;
528 #else
529 const int alpha_offset = 3;
530 #endif
531 int i, j, row_skip;
532 Uint8 *pixels;
533
534 /* Check if we have a 32bit surface */
535 if ( (src==NULL) ||
536 (src->format==NULL) ||
537 (src->format->BytesPerPixel!=4) ) {
538 SDL_SetError("SDL_gfxSetAlpha: Invalid input surface.");
539 return -1;
540 }
541
542 /*
543 * Lock the surface
544 */
545 if (SDL_MUSTLOCK(src)) {
546 if (SDL_LockSurface(src) < 0) {
547 return (-1);
548 }
549 }
550
551 /* Process */
552 pixels = (Uint8 *)src->pixels;
553 row_skip = (src->pitch - (4*src->w));
554 pixels += alpha_offset;
555 for ( i=0; i<src->h; i++ ) {
556 for ( j=0; j<src->w; j++ ) {
557 *pixels = a;
558 pixels += 4;
559 }
560 pixels += row_skip;
561 }
562
563 /*
564 * Unlock surface
565 */
566 if (SDL_MUSTLOCK(src)) {
567 SDL_UnlockSurface(src);
568 }
569
570 return 1;
571 }
572
573 /*!
574 \brief Multiply the alpha channel in a 32bit surface.
575
576 Helper function that multiplies the alpha channel in a 32 bit surface
577 with a constant value. The final alpha is always scaled to the range
578 0-255 (i.e. the factor is a/256).
579
580 Only 32 bit surfaces can be used with this function.
581
582 \param src Pointer to the target surface to change.
583 \param a The alpha value to multiply with. When a is 255, this function is a NoOp.
584
585 \return Returns 1 if alpha was changed, 0 otherwise. Returns -1 if input surface is invalid.
586 */
SDL_gfxMultiplyAlpha(SDL_Surface * src,Uint8 a)587 int SDL_gfxMultiplyAlpha(SDL_Surface *src, Uint8 a)
588 {
589 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
590 const int alpha_offset = 0;
591 #else
592 const int alpha_offset = 3;
593 #endif
594 int i, j, row_skip;
595 Uint8 *pixels;
596
597 /* Check if we have a 32bit surface */
598 if ( (src==NULL) ||
599 (src->format==NULL) ||
600 (src->format->BytesPerPixel!=4) ) {
601 SDL_SetError("SDL_gfxMultiplyAlpha: Invalid input surface.");
602 return -1;
603 }
604
605 /* Check if multiplication is needed */
606 if (a==255) {
607 return 0;
608 }
609
610 /*
611 * Lock the surface
612 */
613 if (SDL_MUSTLOCK(src)) {
614 if (SDL_LockSurface(src) < 0) {
615 return (-1);
616 }
617 }
618
619 /* Process */
620 pixels = (Uint8 *)src->pixels;
621 row_skip = (src->pitch - (4*src->w));
622 pixels += alpha_offset;
623 for ( i=0; i<src->h; i++ ) {
624 for ( j=0; j<src->w; j++ ) {
625 *pixels = (Uint8)(((int)(*pixels)*a)>>8);
626 pixels += 4;
627 }
628 pixels += row_skip;
629 }
630
631 /*
632 * Unlock surface
633 */
634 if (SDL_MUSTLOCK(src)) {
635 SDL_UnlockSurface(src);
636 }
637
638 return 1;
639 }
640