1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#ifndef _SDL_blit_h
25#define _SDL_blit_h
26
27#include "SDL_endian.h"
28
29/* The structure passed to the low level blit functions */
30typedef struct {
31	Uint8 *s_pixels;
32	int s_width;
33	int s_height;
34	int s_skip;
35	Uint8 *d_pixels;
36	int d_width;
37	int d_height;
38	int d_skip;
39	void *aux_data;
40	SDL_PixelFormat *src;
41	Uint8 *table;
42	SDL_PixelFormat *dst;
43} SDL_BlitInfo;
44
45/* The type definition for the low level blit functions */
46typedef void (*SDL_loblit)(SDL_BlitInfo *info);
47
48/* This is the private info structure for software accelerated blits */
49struct private_swaccel {
50	SDL_loblit blit;
51	void *aux_data;
52};
53
54/* Blit mapping definition */
55typedef struct SDL_BlitMap {
56	SDL_Surface *dst;
57	int identity;
58	Uint8 *table;
59	SDL_blit hw_blit;
60	SDL_blit sw_blit;
61	struct private_hwaccel *hw_data;
62	struct private_swaccel *sw_data;
63
64	/* the version count matches the destination; mismatch indicates
65	   an invalid mapping */
66        unsigned int format_version;
67} SDL_BlitMap;
68
69
70/* Functions found in SDL_blit.c */
71extern int SDL_CalculateBlit(SDL_Surface *surface);
72
73/* Functions found in SDL_blit_{0,1,N,A}.c */
74extern SDL_loblit SDL_CalculateBlit0(SDL_Surface *surface, int complex);
75extern SDL_loblit SDL_CalculateBlit1(SDL_Surface *surface, int complex);
76extern SDL_loblit SDL_CalculateBlitN(SDL_Surface *surface, int complex);
77extern SDL_loblit SDL_CalculateAlphaBlit(SDL_Surface *surface, int complex);
78
79/*
80 * Useful macros for blitting routines
81 */
82
83#define FORMAT_EQUAL(A, B)						\
84    ((A)->BitsPerPixel == (B)->BitsPerPixel				\
85     && ((A)->Rmask == (B)->Rmask) && ((A)->Amask == (B)->Amask))
86
87/* Load pixel of the specified format from a buffer and get its R-G-B values */
88/* FIXME: rescale values to 0..255 here? */
89#define RGB_FROM_PIXEL(Pixel, fmt, r, g, b)				\
90{									\
91	r = (((Pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss); 		\
92	g = (((Pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss); 		\
93	b = (((Pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss); 		\
94}
95#define RGB_FROM_RGB565(Pixel, r, g, b)					\
96{									\
97	r = (((Pixel&0xF800)>>11)<<3);		 			\
98	g = (((Pixel&0x07E0)>>5)<<2); 					\
99	b = ((Pixel&0x001F)<<3); 					\
100}
101#define RGB_FROM_RGB555(Pixel, r, g, b)					\
102{									\
103	r = (((Pixel&0x7C00)>>10)<<3);		 			\
104	g = (((Pixel&0x03E0)>>5)<<3); 					\
105	b = ((Pixel&0x001F)<<3); 					\
106}
107#define RGB_FROM_RGB888(Pixel, r, g, b)					\
108{									\
109	r = ((Pixel&0xFF0000)>>16);		 			\
110	g = ((Pixel&0xFF00)>>8);		 			\
111	b = (Pixel&0xFF);			 			\
112}
113#define RETRIEVE_RGB_PIXEL(buf, bpp, Pixel)				   \
114do {									   \
115	switch (bpp) {							   \
116		case 2:							   \
117			Pixel = *((Uint16 *)(buf));			   \
118		break;							   \
119									   \
120		case 3: {						   \
121		        Uint8 *B = (Uint8 *)(buf);			   \
122			if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
123			        Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
124			} else {					   \
125			        Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
126			}						   \
127		}							   \
128		break;							   \
129									   \
130		case 4:							   \
131			Pixel = *((Uint32 *)(buf));			   \
132		break;							   \
133									   \
134		default:						   \
135			Pixel = 0; /* appease gcc */			   \
136		break;							   \
137	}								   \
138} while(0)
139
140#define DISEMBLE_RGB(buf, bpp, fmt, Pixel, r, g, b)			   \
141do {									   \
142	switch (bpp) {							   \
143		case 2:							   \
144			Pixel = *((Uint16 *)(buf));			   \
145		break;							   \
146									   \
147		case 3: {						   \
148		        Uint8 *B = (Uint8 *)buf;			   \
149			if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
150			        Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
151			} else {					   \
152			        Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
153			}						   \
154		}							   \
155		break;							   \
156									   \
157		case 4:							   \
158			Pixel = *((Uint32 *)(buf));			   \
159		break;							   \
160									   \
161	        default:						   \
162		        Pixel = 0;	/* prevent gcc from complaining */ \
163		break;							   \
164	}								   \
165	RGB_FROM_PIXEL(Pixel, fmt, r, g, b);				   \
166} while(0)
167
168/* Assemble R-G-B values into a specified pixel format and store them */
169#ifdef __NDS__ /* FIXME */
170#define PIXEL_FROM_RGB(Pixel, fmt, r, g, b)				\
171{									\
172	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
173		((g>>fmt->Gloss)<<fmt->Gshift)|				\
174		((b>>fmt->Bloss)<<fmt->Bshift) | (1<<15);				\
175}
176#else
177#define PIXEL_FROM_RGB(Pixel, fmt, r, g, b)				\
178{									\
179	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
180		((g>>fmt->Gloss)<<fmt->Gshift)|				\
181		((b>>fmt->Bloss)<<fmt->Bshift);				\
182}
183#endif /* __NDS__ FIXME */
184#define RGB565_FROM_RGB(Pixel, r, g, b)					\
185{									\
186	Pixel = ((r>>3)<<11)|((g>>2)<<5)|(b>>3);			\
187}
188#define RGB555_FROM_RGB(Pixel, r, g, b)					\
189{									\
190	Pixel = ((r>>3)<<10)|((g>>3)<<5)|(b>>3);			\
191}
192#define RGB888_FROM_RGB(Pixel, r, g, b)					\
193{									\
194	Pixel = (r<<16)|(g<<8)|b;					\
195}
196#define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) 				\
197{									\
198	switch (bpp) {							\
199		case 2: {						\
200			Uint16 Pixel;					\
201									\
202			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
203			*((Uint16 *)(buf)) = Pixel;			\
204		}							\
205		break;							\
206									\
207		case 3: {						\
208                        if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
209			        *((buf)+fmt->Rshift/8) = r;		\
210				*((buf)+fmt->Gshift/8) = g;		\
211				*((buf)+fmt->Bshift/8) = b;		\
212			} else {					\
213			        *((buf)+2-fmt->Rshift/8) = r;		\
214				*((buf)+2-fmt->Gshift/8) = g;		\
215				*((buf)+2-fmt->Bshift/8) = b;		\
216			}						\
217		}							\
218		break;							\
219									\
220		case 4: {						\
221			Uint32 Pixel;					\
222									\
223			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
224			*((Uint32 *)(buf)) = Pixel;			\
225		}							\
226		break;							\
227	}								\
228}
229#define ASSEMBLE_RGB_AMASK(buf, bpp, fmt, r, g, b, Amask)		\
230{									\
231	switch (bpp) {							\
232		case 2: {						\
233			Uint16 *bufp;					\
234			Uint16 Pixel;					\
235									\
236			bufp = (Uint16 *)buf;				\
237			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
238			*bufp = Pixel | (*bufp & Amask);		\
239		}							\
240		break;							\
241									\
242		case 3: {						\
243                        if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
244			        *((buf)+fmt->Rshift/8) = r;		\
245				*((buf)+fmt->Gshift/8) = g;		\
246				*((buf)+fmt->Bshift/8) = b;		\
247			} else {					\
248			        *((buf)+2-fmt->Rshift/8) = r;		\
249				*((buf)+2-fmt->Gshift/8) = g;		\
250				*((buf)+2-fmt->Bshift/8) = b;		\
251			}						\
252		}							\
253		break;							\
254									\
255		case 4: {						\
256			Uint32 *bufp;					\
257			Uint32 Pixel;					\
258									\
259			bufp = (Uint32 *)buf;				\
260			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
261			*bufp = Pixel | (*bufp & Amask);		\
262		}							\
263		break;							\
264	}								\
265}
266
267/* FIXME: Should we rescale alpha into 0..255 here? */
268#define RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a)				\
269{									\
270	r = ((Pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss; 		\
271	g = ((Pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss; 		\
272	b = ((Pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss; 		\
273	a = ((Pixel&fmt->Amask)>>fmt->Ashift)<<fmt->Aloss;	 	\
274}
275#define RGBA_FROM_8888(Pixel, fmt, r, g, b, a)	\
276{						\
277	r = (Pixel&fmt->Rmask)>>fmt->Rshift;	\
278	g = (Pixel&fmt->Gmask)>>fmt->Gshift;	\
279	b = (Pixel&fmt->Bmask)>>fmt->Bshift;	\
280	a = (Pixel&fmt->Amask)>>fmt->Ashift;	\
281}
282#define RGBA_FROM_RGBA8888(Pixel, r, g, b, a)				\
283{									\
284	r = (Pixel>>24);						\
285	g = ((Pixel>>16)&0xFF);						\
286	b = ((Pixel>>8)&0xFF);						\
287	a = (Pixel&0xFF);						\
288}
289#define RGBA_FROM_ARGB8888(Pixel, r, g, b, a)				\
290{									\
291	r = ((Pixel>>16)&0xFF);						\
292	g = ((Pixel>>8)&0xFF);						\
293	b = (Pixel&0xFF);						\
294	a = (Pixel>>24);						\
295}
296#define RGBA_FROM_ABGR8888(Pixel, r, g, b, a)				\
297{									\
298	r = (Pixel&0xFF);						\
299	g = ((Pixel>>8)&0xFF);						\
300	b = ((Pixel>>16)&0xFF);						\
301	a = (Pixel>>24);						\
302}
303#define DISEMBLE_RGBA(buf, bpp, fmt, Pixel, r, g, b, a)			   \
304do {									   \
305	switch (bpp) {							   \
306		case 2:							   \
307			Pixel = *((Uint16 *)(buf));			   \
308		break;							   \
309									   \
310		case 3:	{/* FIXME: broken code (no alpha) */		   \
311		        Uint8 *b = (Uint8 *)buf;			   \
312			if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
313			        Pixel = b[0] + (b[1] << 8) + (b[2] << 16); \
314			} else {					   \
315			        Pixel = (b[0] << 16) + (b[1] << 8) + b[2]; \
316			}						   \
317		}							   \
318		break;							   \
319									   \
320		case 4:							   \
321			Pixel = *((Uint32 *)(buf));			   \
322		break;							   \
323									   \
324		default:						   \
325		        Pixel = 0; /* stop gcc complaints */		   \
326		break;							   \
327	}								   \
328	RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a);			   \
329	Pixel &= ~fmt->Amask;						   \
330} while(0)
331
332/* FIXME: this isn't correct, especially for Alpha (maximum != 255) */
333#ifdef __NDS__ /* FIXME */
334#define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a)				\
335{									\
336	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
337		((g>>fmt->Gloss)<<fmt->Gshift)|				\
338		((b>>fmt->Bloss)<<fmt->Bshift)|				\
339		((a>>fmt->Aloss)<<fmt->Ashift) | (1<<15);				\
340}
341#else
342#define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a)				\
343{									\
344	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
345		((g>>fmt->Gloss)<<fmt->Gshift)|				\
346		((b>>fmt->Bloss)<<fmt->Bshift)|				\
347		((a>>fmt->Aloss)<<fmt->Ashift);				\
348}
349#endif /* __NDS__ FIXME */
350#define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a)			\
351{									\
352	switch (bpp) {							\
353		case 2: {						\
354			Uint16 Pixel;					\
355									\
356			PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a);	\
357			*((Uint16 *)(buf)) = Pixel;			\
358		}							\
359		break;							\
360									\
361		case 3: { /* FIXME: broken code (no alpha) */		\
362                        if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
363			        *((buf)+fmt->Rshift/8) = r;		\
364				*((buf)+fmt->Gshift/8) = g;		\
365				*((buf)+fmt->Bshift/8) = b;		\
366			} else {					\
367			        *((buf)+2-fmt->Rshift/8) = r;		\
368				*((buf)+2-fmt->Gshift/8) = g;		\
369				*((buf)+2-fmt->Bshift/8) = b;		\
370			}						\
371		}							\
372		break;							\
373									\
374		case 4: {						\
375			Uint32 Pixel;					\
376									\
377			PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a);	\
378			*((Uint32 *)(buf)) = Pixel;			\
379		}							\
380		break;							\
381	}								\
382}
383
384/* Blend the RGB values of two Pixels based on a source alpha value */
385#define ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB)	\
386do {						\
387	dR = (((sR-dR)*(A)+255)>>8)+dR;		\
388	dG = (((sG-dG)*(A)+255)>>8)+dG;		\
389	dB = (((sB-dB)*(A)+255)>>8)+dB;		\
390} while(0)
391
392
393/* This is a very useful loop for optimizing blitters */
394#if defined(_MSC_VER) && (_MSC_VER == 1300)
395/* There's a bug in the Visual C++ 7 optimizer when compiling this code */
396#else
397#define USE_DUFFS_LOOP
398#endif
399#ifdef USE_DUFFS_LOOP
400
401/* 8-times unrolled loop */
402#define DUFFS_LOOP8(pixel_copy_increment, width)			\
403{ int n = (width+7)/8;							\
404	switch (width & 7) {						\
405	case 0: do {	pixel_copy_increment;				\
406	case 7:		pixel_copy_increment;				\
407	case 6:		pixel_copy_increment;				\
408	case 5:		pixel_copy_increment;				\
409	case 4:		pixel_copy_increment;				\
410	case 3:		pixel_copy_increment;				\
411	case 2:		pixel_copy_increment;				\
412	case 1:		pixel_copy_increment;				\
413		} while ( --n > 0 );					\
414	}								\
415}
416
417/* 4-times unrolled loop */
418#define DUFFS_LOOP4(pixel_copy_increment, width)			\
419{ int n = (width+3)/4;							\
420	switch (width & 3) {						\
421	case 0: do {	pixel_copy_increment;				\
422	case 3:		pixel_copy_increment;				\
423	case 2:		pixel_copy_increment;				\
424	case 1:		pixel_copy_increment;				\
425		} while ( --n > 0 );					\
426	}								\
427}
428
429/* 2 - times unrolled loop */
430#define DUFFS_LOOP_DOUBLE2(pixel_copy_increment,			\
431				double_pixel_copy_increment, width)	\
432{ int n, w = width;							\
433	if( w & 1 ) {							\
434	    pixel_copy_increment;					\
435	    w--;							\
436	}								\
437	if ( w > 0 )	{						\
438	    n = ( w + 2) / 4;						\
439	    switch( w & 2 ) {						\
440	    case 0: do {	double_pixel_copy_increment;		\
441	    case 2:		double_pixel_copy_increment;		\
442		    } while ( --n > 0 );					\
443	    }								\
444	}								\
445}
446
447/* 2 - times unrolled loop 4 pixels */
448#define DUFFS_LOOP_QUATRO2(pixel_copy_increment,			\
449				double_pixel_copy_increment,		\
450				quatro_pixel_copy_increment, width)	\
451{ int n, w = width;								\
452        if(w & 1) {							\
453	  pixel_copy_increment;						\
454	  w--;								\
455	}								\
456	if(w & 2) {							\
457	  double_pixel_copy_increment;					\
458	  w -= 2;							\
459	}								\
460	if ( w > 0 ) {							\
461	    n = ( w + 7 ) / 8;						\
462	    switch( w & 4 ) {						\
463	    case 0: do {	quatro_pixel_copy_increment;		\
464	    case 4:		quatro_pixel_copy_increment;		\
465		    } while ( --n > 0 );					\
466	    }								\
467	}								\
468}
469
470/* Use the 8-times version of the loop by default */
471#define DUFFS_LOOP(pixel_copy_increment, width)				\
472	DUFFS_LOOP8(pixel_copy_increment, width)
473
474#else
475
476/* Don't use Duff's device to unroll loops */
477#define DUFFS_LOOP_DOUBLE2(pixel_copy_increment,			\
478			 double_pixel_copy_increment, width)		\
479{ int n = width;								\
480    if( n & 1 ) {							\
481	pixel_copy_increment;						\
482	n--;								\
483    }									\
484    n=n>>1;								\
485    for(; n > 0; --n) {   						\
486	double_pixel_copy_increment;					\
487    }									\
488}
489
490/* Don't use Duff's device to unroll loops */
491#define DUFFS_LOOP_QUATRO2(pixel_copy_increment,			\
492				double_pixel_copy_increment,		\
493				quatro_pixel_copy_increment, width)	\
494{ int n = width;								\
495        if(n & 1) {							\
496	  pixel_copy_increment;						\
497	  n--;								\
498	}								\
499	if(n & 2) {							\
500	  double_pixel_copy_increment;					\
501	  n -= 2;							\
502	}								\
503	n=n>>2;								\
504	for(; n > 0; --n) {   						\
505	  quatro_pixel_copy_increment;					\
506        }								\
507}
508
509/* Don't use Duff's device to unroll loops */
510#define DUFFS_LOOP(pixel_copy_increment, width)				\
511{ int n;								\
512	for ( n=width; n > 0; --n ) {					\
513		pixel_copy_increment;					\
514	}								\
515}
516#define DUFFS_LOOP8(pixel_copy_increment, width)			\
517	DUFFS_LOOP(pixel_copy_increment, width)
518#define DUFFS_LOOP4(pixel_copy_increment, width)			\
519	DUFFS_LOOP(pixel_copy_increment, width)
520
521#endif /* USE_DUFFS_LOOP */
522
523/* Prevent Visual C++ 6.0 from printing out stupid warnings */
524#if defined(_MSC_VER) && (_MSC_VER >= 600)
525#pragma warning(disable: 4550)
526#endif
527
528#endif /* _SDL_blit_h */
529