src/video/SDL_blit.h
author Sam Lantinga
Fri, 17 Aug 2007 06:21:58 +0000
changeset 2262 bee005ace1bf
parent 2261 c20476d7d7b3
child 2263 900c35d8e8fd
permissions -rw-r--r--
Work in progress: merging new texture features into SDL blit system
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 #ifdef __MMX__
    28 #include <mmintrin.h>
    29 #endif
    30 #ifdef __3dNOW__
    31 #include <mm3dnow.h>
    32 #endif
    33 #ifdef __SSE__
    34 #include <xmmintrin.h>
    35 #endif
    36 #ifdef __SSE2__
    37 #include <emmintrin.h>
    38 #endif
    39 
    40 #include "SDL_cpuinfo.h"
    41 #include "SDL_endian.h"
    42 
    43 /* SDL blit copy flags */
    44 #define SDL_COPY_MODULATE_COLOR     0x0001
    45 #define SDL_COPY_MODULATE_ALPHA     0x0002
    46 #define SDL_COPY_MASK               0x0010
    47 #define SDL_COPY_BLEND              0x0020
    48 #define SDL_COPY_ADD                0x0040
    49 #define SDL_COPY_MOD                0x0080
    50 #define SDL_COPY_COLORKEY           0x0100
    51 #define SDL_COPY_NEAREST            0x0200
    52 
    53 /* SDL blit CPU flags */
    54 #define SDL_CPU_ANY                 0x0000
    55 #define SDL_CPU_MMX                 0x0001
    56 #define SDL_CPU_3DNOW               0x0002
    57 #define SDL_CPU_SSE                 0x0004
    58 #define SDL_CPU_SSE2                0x0008
    59 #define SDL_CPU_ALTIVEC_PREFETCH    0x0010
    60 #define SDL_CPU_ALTIVEC_NOPREFETCH  0x0020
    61 
    62 typedef struct {
    63     Uint8 *src;
    64     int src_w, src_h;
    65     int src_pitch;
    66     Uint8 *dst;
    67     int dst_w, dst_h;
    68     int dst_pitch;
    69     SDL_PixelFormat *src_fmt;
    70     SDL_PixelFormat *dst_fmt;
    71     Uint8 *table;
    72     int flags;
    73     Uint32 colorkey;
    74     Uint8 r, g, b, a;
    75 } SDL_BlitInfo;
    76 
    77 typedef void (SDLCALL * SDL_BlitFunc)(SDL_BlitInfo *info);
    78 
    79 typedef struct {
    80     Uint32 src_format;
    81     Uint32 dst_format;
    82     int flags;
    83     int cpu;
    84     SDL_BlitFunc func;
    85 } SDL_BlitFuncEntry;
    86 
    87 /* Blit mapping definition */
    88 typedef struct SDL_BlitMap
    89 {
    90     SDL_Surface *dst;
    91     int identity;
    92     SDL_blit blit;
    93     void *data;
    94     SDL_BlitInfo info;
    95 
    96     /* the version count matches the destination; mismatch indicates
    97        an invalid mapping */
    98     unsigned int format_version;
    99 } SDL_BlitMap;
   100 
   101 /* Functions found in SDL_blit.c */
   102 extern int SDL_CalculateBlit(SDL_Surface * surface);
   103 
   104 /*
   105  * Useful macros for blitting routines
   106  */
   107 
   108 #if defined(__GNUC__)
   109 #define DECLARE_ALIGNED(t,v,a)  t __attribute__((aligned(a))) v
   110 #elif defined(_MSC_VER)
   111 #define DECLARE_ALIGNED(t,v,a)  __declspec(align(a)) t v
   112 #else
   113 #define DECLARE_ALIGNED(t,v,a)  t v
   114 #endif
   115 
   116 #define FORMAT_EQUAL(A, B)						\
   117     ((A)->BitsPerPixel == (B)->BitsPerPixel				\
   118      && ((A)->Rmask == (B)->Rmask) && ((A)->Amask == (B)->Amask))
   119 
   120 /* Load pixel of the specified format from a buffer and get its R-G-B values */
   121 /* FIXME: rescale values to 0..255 here? */
   122 #define RGB_FROM_PIXEL(Pixel, fmt, r, g, b)				\
   123 {									\
   124 	r = (((Pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss); 		\
   125 	g = (((Pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss); 		\
   126 	b = (((Pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss); 		\
   127 }
   128 #define RGB_FROM_RGB565(Pixel, r, g, b)					\
   129 {									\
   130 	r = (((Pixel&0xF800)>>11)<<3);		 			\
   131 	g = (((Pixel&0x07E0)>>5)<<2); 					\
   132 	b = ((Pixel&0x001F)<<3); 					\
   133 }
   134 #define RGB_FROM_RGB555(Pixel, r, g, b)					\
   135 {									\
   136 	r = (((Pixel&0x7C00)>>10)<<3);		 			\
   137 	g = (((Pixel&0x03E0)>>5)<<3); 					\
   138 	b = ((Pixel&0x001F)<<3); 					\
   139 }
   140 #define RGB_FROM_RGB888(Pixel, r, g, b)					\
   141 {									\
   142 	r = ((Pixel&0xFF0000)>>16);		 			\
   143 	g = ((Pixel&0xFF00)>>8);		 			\
   144 	b = (Pixel&0xFF);			 			\
   145 }
   146 #define RETRIEVE_RGB_PIXEL(buf, bpp, Pixel)				   \
   147 do {									   \
   148 	switch (bpp) {							   \
   149 		case 2:							   \
   150 			Pixel = *((Uint16 *)(buf));			   \
   151 		break;							   \
   152 									   \
   153 		case 3: {						   \
   154 		        Uint8 *B = (Uint8 *)(buf);			   \
   155 			if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   156 			        Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
   157 			} else {					   \
   158 			        Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
   159 			}						   \
   160 		}							   \
   161 		break;							   \
   162 									   \
   163 		case 4:							   \
   164 			Pixel = *((Uint32 *)(buf));			   \
   165 		break;							   \
   166 									   \
   167 		default:						   \
   168 			Pixel = 0; /* appease gcc */			   \
   169 		break;							   \
   170 	}								   \
   171 } while(0)
   172 
   173 #define DISEMBLE_RGB(buf, bpp, fmt, Pixel, r, g, b)			   \
   174 do {									   \
   175 	switch (bpp) {							   \
   176 		case 2:							   \
   177 			Pixel = *((Uint16 *)(buf));			   \
   178 		break;							   \
   179 									   \
   180 		case 3: {						   \
   181 		        Uint8 *B = (Uint8 *)buf;			   \
   182 			if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   183 			        Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
   184 			} else {					   \
   185 			        Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
   186 			}						   \
   187 		}							   \
   188 		break;							   \
   189 									   \
   190 		case 4:							   \
   191 			Pixel = *((Uint32 *)(buf));			   \
   192 		break;							   \
   193 									   \
   194 	        default:						   \
   195 		        Pixel = 0;	/* prevent gcc from complaining */ \
   196 		break;							   \
   197 	}								   \
   198 	RGB_FROM_PIXEL(Pixel, fmt, r, g, b);				   \
   199 } while(0)
   200 
   201 /* Assemble R-G-B values into a specified pixel format and store them */
   202 #define PIXEL_FROM_RGB(Pixel, fmt, r, g, b)				\
   203 {									\
   204 	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
   205 		((g>>fmt->Gloss)<<fmt->Gshift)|				\
   206 		((b>>fmt->Bloss)<<fmt->Bshift);				\
   207 }
   208 #define RGB565_FROM_RGB(Pixel, r, g, b)					\
   209 {									\
   210 	Pixel = ((r>>3)<<11)|((g>>2)<<5)|(b>>3);			\
   211 }
   212 #define RGB555_FROM_RGB(Pixel, r, g, b)					\
   213 {									\
   214 	Pixel = ((r>>3)<<10)|((g>>3)<<5)|(b>>3);			\
   215 }
   216 #define RGB888_FROM_RGB(Pixel, r, g, b)					\
   217 {									\
   218 	Pixel = (r<<16)|(g<<8)|b;					\
   219 }
   220 #define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) 				\
   221 {									\
   222 	switch (bpp) {							\
   223 		case 2: {						\
   224 			Uint16 Pixel;					\
   225 									\
   226 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   227 			*((Uint16 *)(buf)) = Pixel;			\
   228 		}							\
   229 		break;							\
   230 									\
   231 		case 3: {						\
   232                         if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
   233 			        *((buf)+fmt->Rshift/8) = r;		\
   234 				*((buf)+fmt->Gshift/8) = g;		\
   235 				*((buf)+fmt->Bshift/8) = b;		\
   236 			} else {					\
   237 			        *((buf)+2-fmt->Rshift/8) = r;		\
   238 				*((buf)+2-fmt->Gshift/8) = g;		\
   239 				*((buf)+2-fmt->Bshift/8) = b;		\
   240 			}						\
   241 		}							\
   242 		break;							\
   243 									\
   244 		case 4: {						\
   245 			Uint32 Pixel;					\
   246 									\
   247 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   248 			*((Uint32 *)(buf)) = Pixel;			\
   249 		}							\
   250 		break;							\
   251 	}								\
   252 }
   253 #define ASSEMBLE_RGB_AMASK(buf, bpp, fmt, r, g, b, Amask)		\
   254 {									\
   255 	switch (bpp) {							\
   256 		case 2: {						\
   257 			Uint16 *bufp;					\
   258 			Uint16 Pixel;					\
   259 									\
   260 			bufp = (Uint16 *)buf;				\
   261 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   262 			*bufp = Pixel | (*bufp & Amask);		\
   263 		}							\
   264 		break;							\
   265 									\
   266 		case 3: {						\
   267                         if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
   268 			        *((buf)+fmt->Rshift/8) = r;		\
   269 				*((buf)+fmt->Gshift/8) = g;		\
   270 				*((buf)+fmt->Bshift/8) = b;		\
   271 			} else {					\
   272 			        *((buf)+2-fmt->Rshift/8) = r;		\
   273 				*((buf)+2-fmt->Gshift/8) = g;		\
   274 				*((buf)+2-fmt->Bshift/8) = b;		\
   275 			}						\
   276 		}							\
   277 		break;							\
   278 									\
   279 		case 4: {						\
   280 			Uint32 *bufp;					\
   281 			Uint32 Pixel;					\
   282 									\
   283 			bufp = (Uint32 *)buf;				\
   284 			PIXEL_FROM_RGB(Pixel, fmt, r, g, b);		\
   285 			*bufp = Pixel | (*bufp & Amask);		\
   286 		}							\
   287 		break;							\
   288 	}								\
   289 }
   290 
   291 /* FIXME: Should we rescale alpha into 0..255 here? */
   292 #define RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a)				\
   293 {									\
   294 	r = ((Pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss; 		\
   295 	g = ((Pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss; 		\
   296 	b = ((Pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss; 		\
   297 	a = ((Pixel&fmt->Amask)>>fmt->Ashift)<<fmt->Aloss;	 	\
   298 }
   299 #define RGBA_FROM_8888(Pixel, fmt, r, g, b, a)	\
   300 {						\
   301 	r = (Pixel&fmt->Rmask)>>fmt->Rshift;	\
   302 	g = (Pixel&fmt->Gmask)>>fmt->Gshift;	\
   303 	b = (Pixel&fmt->Bmask)>>fmt->Bshift;	\
   304 	a = (Pixel&fmt->Amask)>>fmt->Ashift;	\
   305 }
   306 #define RGBA_FROM_RGBA8888(Pixel, r, g, b, a)				\
   307 {									\
   308 	r = (Pixel>>24);						\
   309 	g = ((Pixel>>16)&0xFF);						\
   310 	b = ((Pixel>>8)&0xFF);						\
   311 	a = (Pixel&0xFF);						\
   312 }
   313 #define RGBA_FROM_ARGB8888(Pixel, r, g, b, a)				\
   314 {									\
   315 	r = ((Pixel>>16)&0xFF);						\
   316 	g = ((Pixel>>8)&0xFF);						\
   317 	b = (Pixel&0xFF);						\
   318 	a = (Pixel>>24);						\
   319 }
   320 #define RGBA_FROM_ABGR8888(Pixel, r, g, b, a)				\
   321 {									\
   322 	r = (Pixel&0xFF);						\
   323 	g = ((Pixel>>8)&0xFF);						\
   324 	b = ((Pixel>>16)&0xFF);						\
   325 	a = (Pixel>>24);						\
   326 }
   327 #define DISEMBLE_RGBA(buf, bpp, fmt, Pixel, r, g, b, a)			   \
   328 do {									   \
   329 	switch (bpp) {							   \
   330 		case 2:							   \
   331 			Pixel = *((Uint16 *)(buf));			   \
   332 		break;							   \
   333 									   \
   334 		case 3:	{/* FIXME: broken code (no alpha) */		   \
   335 		        Uint8 *b = (Uint8 *)buf;			   \
   336 			if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		   \
   337 			        Pixel = b[0] + (b[1] << 8) + (b[2] << 16); \
   338 			} else {					   \
   339 			        Pixel = (b[0] << 16) + (b[1] << 8) + b[2]; \
   340 			}						   \
   341 		}							   \
   342 		break;							   \
   343 									   \
   344 		case 4:							   \
   345 			Pixel = *((Uint32 *)(buf));			   \
   346 		break;							   \
   347 									   \
   348 		default:						   \
   349 		        Pixel = 0; /* stop gcc complaints */		   \
   350 		break;							   \
   351 	}								   \
   352 	RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a);			   \
   353 	Pixel &= ~fmt->Amask;						   \
   354 } while(0)
   355 
   356 /* FIXME: this isn't correct, especially for Alpha (maximum != 255) */
   357 #define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a)				\
   358 {									\
   359 	Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|				\
   360 		((g>>fmt->Gloss)<<fmt->Gshift)|				\
   361 		((b>>fmt->Bloss)<<fmt->Bshift)|				\
   362 		((a>>fmt->Aloss)<<fmt->Ashift);				\
   363 }
   364 #define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a)			\
   365 {									\
   366 	switch (bpp) {							\
   367 		case 2: {						\
   368 			Uint16 Pixel;					\
   369 									\
   370 			PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a);	\
   371 			*((Uint16 *)(buf)) = Pixel;			\
   372 		}							\
   373 		break;							\
   374 									\
   375 		case 3: { /* FIXME: broken code (no alpha) */		\
   376                         if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {		\
   377 			        *((buf)+fmt->Rshift/8) = r;		\
   378 				*((buf)+fmt->Gshift/8) = g;		\
   379 				*((buf)+fmt->Bshift/8) = b;		\
   380 			} else {					\
   381 			        *((buf)+2-fmt->Rshift/8) = r;		\
   382 				*((buf)+2-fmt->Gshift/8) = g;		\
   383 				*((buf)+2-fmt->Bshift/8) = b;		\
   384 			}						\
   385 		}							\
   386 		break;							\
   387 									\
   388 		case 4: {						\
   389 			Uint32 Pixel;					\
   390 									\
   391 			PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a);	\
   392 			*((Uint32 *)(buf)) = Pixel;			\
   393 		}							\
   394 		break;							\
   395 	}								\
   396 }
   397 
   398 /* Blend the RGB values of two Pixels based on a source alpha value */
   399 #define ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB)	\
   400 do {						\
   401 	dR = (((sR-dR)*(A))>>8)+dR;		\
   402 	dG = (((sG-dG)*(A))>>8)+dG;		\
   403 	dB = (((sB-dB)*(A))>>8)+dB;		\
   404 } while(0)
   405 
   406 /* Blend the RGB values of two Pixels based on a source alpha value */
   407 #define ACCURATE_ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB)	\
   408 do {						\
   409     unsigned tR, tG, tB, tA; \
   410     tA = 255 - sA; \
   411     tR = 1 + (sR * sA) + (dR * tA); \
   412     dR = (tR + (tR >> 8)) >> 8; \
   413     tG = 1 + (sG * sA) + (dG * tA); \
   414     dG = (tG + (tG >> 8)) >> 8; \
   415     tB = 1 + (sB * sA) + (dB * tA); \
   416     dB = (tB + (tB >> 8)) >> 8; \
   417 } while(0)
   418 
   419 
   420 /* This is a very useful loop for optimizing blitters */
   421 #if defined(_MSC_VER) && (_MSC_VER == 1300)
   422 /* There's a bug in the Visual C++ 7 optimizer when compiling this code */
   423 #else
   424 #define USE_DUFFS_LOOP
   425 #endif
   426 #ifdef USE_DUFFS_LOOP
   427 
   428 /* 8-times unrolled loop */
   429 #define DUFFS_LOOP8(pixel_copy_increment, width)			\
   430 { int n = (width+7)/8;							\
   431 	switch (width & 7) {						\
   432 	case 0: do {	pixel_copy_increment;				\
   433 	case 7:		pixel_copy_increment;				\
   434 	case 6:		pixel_copy_increment;				\
   435 	case 5:		pixel_copy_increment;				\
   436 	case 4:		pixel_copy_increment;				\
   437 	case 3:		pixel_copy_increment;				\
   438 	case 2:		pixel_copy_increment;				\
   439 	case 1:		pixel_copy_increment;				\
   440 		} while ( --n > 0 );					\
   441 	}								\
   442 }
   443 
   444 /* 4-times unrolled loop */
   445 #define DUFFS_LOOP4(pixel_copy_increment, width)			\
   446 { int n = (width+3)/4;							\
   447 	switch (width & 3) {						\
   448 	case 0: do {	pixel_copy_increment;				\
   449 	case 3:		pixel_copy_increment;				\
   450 	case 2:		pixel_copy_increment;				\
   451 	case 1:		pixel_copy_increment;				\
   452 		} while ( --n > 0 );					\
   453 	}								\
   454 }
   455 
   456 /* 2 - times unrolled loop */
   457 #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment,			\
   458 				double_pixel_copy_increment, width)	\
   459 { int n, w = width;							\
   460 	if( w & 1 ) {							\
   461 	    pixel_copy_increment;					\
   462 	    w--;							\
   463 	}								\
   464 	if ( w > 0 )	{						\
   465 	    n = ( w + 2) / 4;						\
   466 	    switch( w & 2 ) {						\
   467 	    case 0: do {	double_pixel_copy_increment;		\
   468 	    case 2:		double_pixel_copy_increment;		\
   469 		    } while ( --n > 0 );					\
   470 	    }								\
   471 	}								\
   472 }
   473 
   474 /* 2 - times unrolled loop 4 pixels */
   475 #define DUFFS_LOOP_QUATRO2(pixel_copy_increment,			\
   476 				double_pixel_copy_increment,		\
   477 				quatro_pixel_copy_increment, width)	\
   478 { int n, w = width;								\
   479         if(w & 1) {							\
   480 	  pixel_copy_increment;						\
   481 	  w--;								\
   482 	}								\
   483 	if(w & 2) {							\
   484 	  double_pixel_copy_increment;					\
   485 	  w -= 2;							\
   486 	}								\
   487 	if ( w > 0 ) {							\
   488 	    n = ( w + 7 ) / 8;						\
   489 	    switch( w & 4 ) {						\
   490 	    case 0: do {	quatro_pixel_copy_increment;		\
   491 	    case 4:		quatro_pixel_copy_increment;		\
   492 		    } while ( --n > 0 );					\
   493 	    }								\
   494 	}								\
   495 }
   496 
   497 /* Use the 8-times version of the loop by default */
   498 #define DUFFS_LOOP(pixel_copy_increment, width)				\
   499 	DUFFS_LOOP8(pixel_copy_increment, width)
   500 
   501 #else
   502 
   503 /* Don't use Duff's device to unroll loops */
   504 #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment,			\
   505 			 double_pixel_copy_increment, width)		\
   506 { int n = width;								\
   507     if( n & 1 ) {							\
   508 	pixel_copy_increment;						\
   509 	n--;								\
   510     }									\
   511     n=n>>1;								\
   512     for(; n > 0; --n) {   						\
   513 	double_pixel_copy_increment;					\
   514     }									\
   515 }
   516 
   517 /* Don't use Duff's device to unroll loops */
   518 #define DUFFS_LOOP_QUATRO2(pixel_copy_increment,			\
   519 				double_pixel_copy_increment,		\
   520 				quatro_pixel_copy_increment, width)	\
   521 { int n = width;								\
   522         if(n & 1) {							\
   523 	  pixel_copy_increment;						\
   524 	  n--;								\
   525 	}								\
   526 	if(n & 2) {							\
   527 	  double_pixel_copy_increment;					\
   528 	  n -= 2;							\
   529 	}								\
   530 	n=n>>2;								\
   531 	for(; n > 0; --n) {   						\
   532 	  quatro_pixel_copy_increment;					\
   533         }								\
   534 }
   535 
   536 /* Don't use Duff's device to unroll loops */
   537 #define DUFFS_LOOP(pixel_copy_increment, width)				\
   538 { int n;								\
   539 	for ( n=width; n > 0; --n ) {					\
   540 		pixel_copy_increment;					\
   541 	}								\
   542 }
   543 #define DUFFS_LOOP8(pixel_copy_increment, width)			\
   544 	DUFFS_LOOP(pixel_copy_increment, width)
   545 #define DUFFS_LOOP4(pixel_copy_increment, width)			\
   546 	DUFFS_LOOP(pixel_copy_increment, width)
   547 
   548 #endif /* USE_DUFFS_LOOP */
   549 
   550 /* Prevent Visual C++ 6.0 from printing out stupid warnings */
   551 #if defined(_MSC_VER) && (_MSC_VER >= 600)
   552 #pragma warning(disable: 4550)
   553 #endif
   554 
   555 #endif /* _SDL_blit_h */
   556 /* vi: set ts=4 sw=4 expandtab: */