test/testalpha.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 06 May 2004 15:55:06 +0000
changeset 886 05c551e5bc64
parent 691 609543e2b3a1
child 1151 be9c9c8f6d53
permissions -rw-r--r--
Date: Sat, 24 Apr 2004 15:13:32 +0300
From: "Mike Gorchak"
Subject: SDL updates for the QNX6

1. Updated the README.QNX
2. Updated libtool scripts, which are shipped with SDL for QNX6 support.
3. Added some code to support the new QNX 6.3.0, which is in beta now.
4. Added code to detect the hw features, which driver supports.
5. Added hw alpha blits code.
6. Fixed bug when application switches to fullscreen more the 2 times. (afte\
r that window becames always stay on top).
7. Updated a bit README for the tests.
8. Added information about acceleration show in the testalpha.c test.
9. Added small fixes to the testoverlay2.c test.
10. Added alpha and cc+alpha blits benchmarks to the testvidinfo.c test.
     1 
     2 /* Simple program:  Fill a colormap with gray and stripe it down the screen,
     3 		    Then move an alpha valued sprite around the screen.
     4  */
     5 
     6 #include <stdio.h>
     7 #include <stdlib.h>
     8 #include <string.h>
     9 #include <math.h>
    10 
    11 #include "SDL.h"
    12 
    13 #define FRAME_TICKS	(1000/30)		/* 30 frames/second */
    14 
    15 /* Create a "light" -- a yellowish surface with variable alpha */
    16 SDL_Surface *CreateLight(SDL_Surface *screen, int radius)
    17 {
    18 	Uint8  trans, alphamask;
    19 	int    range, addition;
    20 	int    xdist, ydist;
    21 	Uint16 x, y;
    22 	Uint16 skip;
    23 	Uint32 pixel;
    24 	SDL_Surface *light;
    25 
    26 #ifdef LIGHT_16BIT
    27 	Uint16 *buf;
    28 
    29 	/* Create a 16 (4/4/4/4) bpp square with a full 4-bit alpha channel */
    30 	/* Note: this isn't any faster than a 32 bit alpha surface */
    31 	alphamask = 0x0000000F;
    32 	light = SDL_CreateRGBSurface(SDL_SWSURFACE, 2*radius, 2*radius, 16,
    33 			0x0000F000, 0x00000F00, 0x000000F0, alphamask);
    34 #else
    35 	Uint32 *buf;
    36 
    37 	/* Create a 32 (8/8/8/8) bpp square with a full 8-bit alpha channel */
    38 	alphamask = 0x000000FF;
    39 	light = SDL_CreateRGBSurface(SDL_SWSURFACE, 2*radius, 2*radius, 32,
    40 			0xFF000000, 0x00FF0000, 0x0000FF00, alphamask);
    41 	if ( light == NULL ) {
    42 		fprintf(stderr, "Couldn't create light: %s\n", SDL_GetError());
    43 		return(NULL);
    44 	}
    45 #endif
    46 
    47 	/* Fill with a light yellow-orange color */
    48 	skip = light->pitch-(light->w*light->format->BytesPerPixel);
    49 #ifdef LIGHT_16BIT
    50 	buf = (Uint16 *)light->pixels;
    51 #else
    52 	buf = (Uint32 *)light->pixels;
    53 #endif
    54         /* Get a tranparent pixel value - we'll add alpha later */
    55 	pixel = SDL_MapRGBA(light->format, 0xFF, 0xDD, 0x88, 0);
    56 	for ( y=0; y<light->h; ++y ) {
    57 		for ( x=0; x<light->w; ++x ) {
    58 			*buf++ = pixel;
    59 		}
    60 		buf += skip;	/* Almost always 0, but just in case... */
    61 	}
    62 
    63 	/* Calculate alpha values for the surface. */
    64 #ifdef LIGHT_16BIT
    65 	buf = (Uint16 *)light->pixels;
    66 #else
    67 	buf = (Uint32 *)light->pixels;
    68 #endif
    69 	for ( y=0; y<light->h; ++y ) {
    70 		for ( x=0; x<light->w; ++x ) {
    71 			/* Slow distance formula (from center of light) */
    72 			xdist = x-(light->w/2);
    73 			ydist = y-(light->h/2);
    74 			range = (int)sqrt(xdist*xdist+ydist*ydist);
    75 
    76 			/* Scale distance to range of transparency (0-255) */
    77 			if ( range > radius ) {
    78 				trans = alphamask;
    79 			} else {
    80 				/* Increasing transparency with distance */
    81 				trans = (Uint8)((range*alphamask)/radius);
    82 
    83 				/* Lights are very transparent */
    84 				addition = (alphamask+1)/8;
    85 				if ( (int)trans+addition > alphamask ) {
    86 					trans = alphamask;
    87 				} else {
    88 					trans += addition;
    89 				}
    90 			}
    91 			/* We set the alpha component as the right N bits */
    92 			*buf++ |= (255-trans);
    93 		}
    94 		buf += skip;	/* Almost always 0, but just in case... */
    95 	}
    96 	/* Enable RLE acceleration of this alpha surface */
    97 	SDL_SetAlpha(light, SDL_SRCALPHA|SDL_RLEACCEL, 0);
    98 
    99 	/* We're done! */
   100 	return(light);
   101 }
   102 
   103 static Uint32 flashes = 0;
   104 static Uint32 flashtime = 0;
   105 
   106 void FlashLight(SDL_Surface *screen, SDL_Surface *light, int x, int y)
   107 {
   108 	SDL_Rect position;
   109 	Uint32   ticks1;
   110 	Uint32   ticks2;
   111 
   112 	/* Easy, center light */
   113 	position.x = x-(light->w/2);
   114 	position.y = y-(light->h/2);
   115 	position.w = light->w;
   116 	position.h = light->h;
   117 	ticks1 = SDL_GetTicks();
   118 	SDL_BlitSurface(light, NULL, screen, &position);
   119 	ticks2 = SDL_GetTicks();
   120 	SDL_UpdateRects(screen, 1, &position);
   121 	++flashes;
   122 
   123 	/* Update time spend doing alpha blitting */
   124 	flashtime += (ticks2-ticks1);
   125 }
   126 
   127 static int sprite_visible = 0;
   128 static SDL_Surface *sprite;
   129 static SDL_Surface *backing;
   130 static SDL_Rect    position;
   131 static int         x_vel, y_vel;
   132 static int	   alpha_vel;
   133 
   134 int LoadSprite(SDL_Surface *screen, char *file)
   135 {
   136 	SDL_Surface *converted;
   137 
   138 	/* Load the sprite image */
   139 	sprite = SDL_LoadBMP(file);
   140 	if ( sprite == NULL ) {
   141 		fprintf(stderr, "Couldn't load %s: %s", file, SDL_GetError());
   142 		return(-1);
   143 	}
   144 
   145 	/* Set transparent pixel as the pixel at (0,0) */
   146 	if ( sprite->format->palette ) {
   147 		SDL_SetColorKey(sprite, SDL_SRCCOLORKEY,
   148 						*(Uint8 *)sprite->pixels);
   149 	}
   150 
   151 	/* Convert sprite to video format */
   152 	converted = SDL_DisplayFormat(sprite);
   153 	SDL_FreeSurface(sprite);
   154 	if ( converted == NULL ) {
   155 		fprintf(stderr, "Couldn't convert background: %s\n",
   156 							SDL_GetError());
   157 		return(-1);
   158 	}
   159 	sprite = converted;
   160 
   161 	/* Create the background */
   162 	backing = SDL_CreateRGBSurface(SDL_SWSURFACE, sprite->w, sprite->h, 8,
   163 								0, 0, 0, 0);
   164 	if ( backing == NULL ) {
   165 		fprintf(stderr, "Couldn't create background: %s\n",
   166 							SDL_GetError());
   167 		SDL_FreeSurface(sprite);
   168 		return(-1);
   169 	}
   170 
   171 	/* Convert background to video format */
   172 	converted = SDL_DisplayFormat(backing);
   173 	SDL_FreeSurface(backing);
   174 	if ( converted == NULL ) {
   175 		fprintf(stderr, "Couldn't convert background: %s\n",
   176 							SDL_GetError());
   177 		SDL_FreeSurface(sprite);
   178 		return(-1);
   179 	}
   180 	backing = converted;
   181 
   182 	/* Set the initial position of the sprite */
   183 	position.x = (screen->w-sprite->w)/2;
   184 	position.y = (screen->h-sprite->h)/2;
   185 	position.w = sprite->w;
   186 	position.h = sprite->h;
   187 	x_vel = 0; y_vel = 0;
   188 	alpha_vel = 1;
   189 
   190 	/* We're ready to roll. :) */
   191 	return(0);
   192 }
   193 
   194 void AttractSprite(Uint16 x, Uint16 y)
   195 {
   196 	x_vel = ((int)x-position.x)/10;
   197 	y_vel = ((int)y-position.y)/10;
   198 }
   199 
   200 void MoveSprite(SDL_Surface *screen, SDL_Surface *light)
   201 {
   202 	SDL_Rect updates[2];
   203 	int alpha;
   204 
   205 	/* Erase the sprite if it was visible */
   206 	if ( sprite_visible ) {
   207 		updates[0] = position;
   208 		SDL_BlitSurface(backing, NULL, screen, &updates[0]);
   209 	} else {
   210 		updates[0].x = 0; updates[0].y = 0;
   211 		updates[0].w = 0; updates[0].h = 0;
   212 		sprite_visible = 1;
   213 	}
   214 
   215 	/* Since the sprite is off the screen, we can do other drawing
   216 	   without being overwritten by the saved area behind the sprite.
   217 	 */
   218 	if ( light != NULL ) {
   219 		int x, y;
   220 
   221 		SDL_GetMouseState(&x, &y);
   222 		FlashLight(screen, light, x, y);
   223 	}
   224 	   
   225 	/* Move the sprite, bounce at the wall */
   226 	position.x += x_vel;
   227 	if ( (position.x < 0) || (position.x >= screen->w) ) {
   228 		x_vel = -x_vel;
   229 		position.x += x_vel;
   230 	}
   231 	position.y += y_vel;
   232 	if ( (position.y < 0) || (position.y >= screen->h) ) {
   233 		y_vel = -y_vel;
   234 		position.y += y_vel;
   235 	}
   236 
   237 	/* Update transparency (fade in and out) */
   238 	alpha = sprite->format->alpha;
   239 	if ( (alpha+alpha_vel) < 0 ) {
   240 		alpha_vel = -alpha_vel;
   241 	} else
   242 	if ( (alpha+alpha_vel) > 255 ) {
   243 		alpha_vel = -alpha_vel;
   244 	}
   245 	SDL_SetAlpha(sprite, SDL_SRCALPHA, (Uint8)(alpha+alpha_vel));
   246 
   247 	/* Save the area behind the sprite */
   248 	updates[1] = position;
   249 	SDL_BlitSurface(screen, &updates[1], backing, NULL);
   250 	
   251 	/* Blit the sprite onto the screen */
   252 	updates[1] = position;
   253 	SDL_BlitSurface(sprite, NULL, screen, &updates[1]);
   254 
   255 	/* Make it so! */
   256 	SDL_UpdateRects(screen, 2, updates);
   257 }
   258 
   259 void WarpSprite(SDL_Surface *screen, int x, int y)
   260 {
   261 	SDL_Rect updates[2];
   262 
   263 	/* Erase, move, Draw, update */
   264 	updates[0] = position;
   265 	SDL_BlitSurface(backing, NULL, screen, &updates[0]);
   266 	position.x = x-sprite->w/2;	/* Center about X */
   267 	position.y = y-sprite->h/2;	/* Center about Y */
   268 	updates[1] = position;
   269 	SDL_BlitSurface(screen, &updates[1], backing, NULL);
   270 	updates[1] = position;
   271 	SDL_BlitSurface(sprite, NULL, screen, &updates[1]);
   272 	SDL_UpdateRects(screen, 2, updates);
   273 }
   274 
   275 int main(int argc, char *argv[])
   276 {
   277 	const SDL_VideoInfo *info;
   278 	SDL_Surface *screen;
   279 	Uint8  video_bpp;
   280 	Uint32 videoflags;
   281 	Uint8 *buffer;
   282 	int    i, k, done;
   283 	SDL_Event event;
   284 	SDL_Surface *light;
   285 	int mouse_pressed;
   286 	Uint32 ticks, lastticks;
   287 	Uint16 *buffer16;
   288         Uint16 color;
   289         Uint8  gradient;
   290 
   291 
   292 	/* Initialize SDL */
   293 	if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
   294 		fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
   295 		exit(1);
   296 	}
   297 	atexit(SDL_Quit);
   298 
   299 	/* Alpha blending doesn't work well at 8-bit color */
   300 	info = SDL_GetVideoInfo();
   301 	if ( info->vfmt->BitsPerPixel > 8 ) {
   302 		video_bpp = info->vfmt->BitsPerPixel;
   303 	} else {
   304 		video_bpp = 16;
   305                 fprintf(stderr, "forced 16 bpp mode\n");
   306 	}
   307 	videoflags = SDL_SWSURFACE;
   308 	while ( argc > 1 ) {
   309 		--argc;
   310 		if ( strcmp(argv[argc-1], "-bpp") == 0 ) {
   311 			video_bpp = atoi(argv[argc]);
   312                         if (video_bpp<=8) {
   313                             video_bpp=16;
   314                             fprintf(stderr, "forced 16 bpp mode\n");
   315                         }
   316 			--argc;
   317 		} else
   318 		if ( strcmp(argv[argc], "-hw") == 0 ) {
   319 			videoflags |= SDL_HWSURFACE;
   320 		} else
   321 		if ( strcmp(argv[argc], "-warp") == 0 ) {
   322 			videoflags |= SDL_HWPALETTE;
   323 		} else
   324 		if ( strcmp(argv[argc], "-fullscreen") == 0 ) {
   325 			videoflags |= SDL_FULLSCREEN;
   326 		} else {
   327 			fprintf(stderr, 
   328 			"Usage: %s [-bpp N] [-warp] [-hw] [-fullscreen]\n",
   329 								argv[0]);
   330 			exit(1);
   331 		}
   332 	}
   333 
   334 	/* Set 640x480 video mode */
   335 	if ( (screen=SDL_SetVideoMode(640,480,video_bpp,videoflags)) == NULL ) {
   336 		fprintf(stderr, "Couldn't set 640x480x%d video mode: %s\n",
   337 						video_bpp, SDL_GetError());
   338 		exit(2);
   339 	}
   340 
   341 	/* Set the surface pixels and refresh! */
   342 	if ( SDL_LockSurface(screen) < 0 ) {
   343 		fprintf(stderr, "Couldn't lock the display surface: %s\n",
   344 							SDL_GetError());
   345 		exit(2);
   346 	}
   347 	buffer=(Uint8 *)screen->pixels;
   348 	if (screen->format->BytesPerPixel!=2) {
   349 		for ( i=0; i<screen->h; ++i ) {
   350 			memset(buffer,(i*255)/screen->h, screen->pitch);
   351 			buffer += screen->pitch;
   352 		}
   353 	}
   354         else
   355         {
   356 		for ( i=0; i<screen->h; ++i ) {
   357 			gradient=((i*255)/screen->h);
   358                         color = SDL_MapRGB(screen->format, gradient, gradient, gradient);
   359                         buffer16=(Uint16*)buffer;
   360                         for (k=0; k<screen->w; k++)
   361                         {
   362                             *(buffer16+k)=color;
   363                         }
   364 			buffer += screen->pitch;
   365 		}
   366         }
   367 
   368 	SDL_UnlockSurface(screen);
   369 	SDL_UpdateRect(screen, 0, 0, 0, 0);
   370 
   371 	/* Create the light */
   372 	light = CreateLight(screen, 82);
   373 	if ( light == NULL ) {
   374 		exit(1);
   375 	}
   376 
   377 	/* Load the sprite */
   378 	if ( LoadSprite(screen, "icon.bmp") < 0 ) {
   379 		SDL_FreeSurface(light);
   380 		exit(1);
   381 	}
   382 
   383 	/* Print out information about our surfaces */
   384 	printf("Screen is at %d bits per pixel\n",screen->format->BitsPerPixel);
   385 	if ( (screen->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
   386 		printf("Screen is in video memory\n");
   387 	} else {
   388 		printf("Screen is in system memory\n");
   389 	}
   390 	if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
   391 		printf("Screen has double-buffering enabled\n");
   392 	}
   393 	if ( (sprite->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
   394 		printf("Sprite is in video memory\n");
   395 	} else {
   396 		printf("Sprite is in system memory\n");
   397 	}
   398 
   399 	/* Run a sample blit to trigger blit acceleration */
   400 	{ SDL_Rect dst;
   401 		dst.x = 0;
   402 		dst.y = 0;
   403 		dst.w = sprite->w;
   404 		dst.h = sprite->h;
   405 		SDL_BlitSurface(sprite, NULL, screen, &dst);
   406 		SDL_FillRect(screen, &dst, 0);
   407 	}
   408 	if ( (sprite->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
   409 		printf("Sprite blit uses hardware alpha acceleration\n");
   410 	} else {
   411 		printf("Sprite blit dosn't uses hardware alpha acceleration\n");
   412 	}
   413 
   414 	/* Set a clipping rectangle to clip the outside edge of the screen */
   415 	{ SDL_Rect clip;
   416 		clip.x = 32;
   417 		clip.y = 32;
   418 		clip.w = screen->w-(2*32);
   419 		clip.h = screen->h-(2*32);
   420 		SDL_SetClipRect(screen, &clip);
   421 	}
   422 
   423 	/* Wait for a keystroke */
   424 	lastticks = SDL_GetTicks();
   425 	done = 0;
   426 	mouse_pressed = 0;
   427 	while ( !done ) {
   428 		/* Update the frame -- move the sprite */
   429 		if ( mouse_pressed ) {
   430 			MoveSprite(screen, light);
   431 			mouse_pressed = 0;
   432 		} else {
   433 			MoveSprite(screen, NULL);
   434 		}
   435 
   436 		/* Slow down the loop to 30 frames/second */
   437 		ticks = SDL_GetTicks();
   438 		if ( (ticks-lastticks) < FRAME_TICKS ) {
   439 #ifdef CHECK_SLEEP_GRANULARITY
   440 fprintf(stderr, "Sleeping %d ticks\n", FRAME_TICKS-(ticks-lastticks));
   441 #endif
   442 			SDL_Delay(FRAME_TICKS-(ticks-lastticks));
   443 #ifdef CHECK_SLEEP_GRANULARITY
   444 fprintf(stderr, "Slept %d ticks\n", (SDL_GetTicks()-ticks));
   445 #endif
   446 		}
   447 		lastticks = ticks;
   448 
   449 		/* Check for events */
   450 		while ( SDL_PollEvent(&event) ) {
   451 			switch (event.type) {
   452 				/* Attract sprite while mouse is held down */
   453 				case SDL_MOUSEMOTION:
   454 					if (event.motion.state != 0) {
   455 						AttractSprite(event.motion.x,
   456 								event.motion.y);
   457 						mouse_pressed = 1;
   458 					}
   459 					break;
   460 				case SDL_MOUSEBUTTONDOWN:
   461 					if ( event.button.button == 1 ) {
   462 						AttractSprite(event.button.x,
   463 						              event.button.y);
   464 						mouse_pressed = 1;
   465 					} else {
   466 						SDL_Rect area;
   467 
   468 						area.x = event.button.x-16;
   469 						area.y = event.button.y-16;
   470 						area.w = 32;
   471 						area.h = 32;
   472 						SDL_FillRect(screen, &area, 0);
   473 						SDL_UpdateRects(screen,1,&area);
   474 					}
   475 					break;
   476 				case SDL_KEYDOWN:
   477 					/* Any keypress quits the app... */
   478 				case SDL_QUIT:
   479 					done = 1;
   480 					break;
   481 				default:
   482 					break;
   483 			}
   484 		}
   485 	}
   486 	SDL_FreeSurface(light);
   487 	SDL_FreeSurface(sprite);
   488 	SDL_FreeSurface(backing);
   489 
   490 	/* Print out some timing information */
   491 	if ( flashes > 0 ) {
   492 		printf("%d alpha blits, ~%4.4f ms per blit\n", 
   493 			flashes, (float)flashtime/flashes);
   494 	}
   495 	return(0);
   496 }