test/testalpha.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 09 May 2006 07:26:58 +0000
changeset 1790 828a17e05192
parent 1779 67fc81efcfc3
child 1662 782fd950bd46
child 1895 c121d94672cb
child 3868 b2f59aadec0d
permissions -rw-r--r--
Date: Mon, 8 May 2006 14:19:30 -0700
From: Bob Ippolito
Subject: SDL trunk (r2346) and Mac OS X

The current state of the trunk doesn't quite compile on Mac OS X,
I've attached a series of patches that gets it to compile and kills a
few warnings.

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