test/testalpha.c
changeset 0 74212992fb08
child 691 609543e2b3a1
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/test/testalpha.c	Thu Apr 26 16:45:43 2001 +0000
     1.3 @@ -0,0 +1,440 @@
     1.4 +
     1.5 +/* Simple program:  Fill a colormap with gray and stripe it down the screen,
     1.6 +		    Then move an alpha valued sprite around the screen.
     1.7 + */
     1.8 +
     1.9 +#include <stdio.h>
    1.10 +#include <stdlib.h>
    1.11 +#include <string.h>
    1.12 +#include <math.h>
    1.13 +
    1.14 +#include "SDL.h"
    1.15 +
    1.16 +#define FRAME_TICKS	(1000/30)		/* 30 frames/second */
    1.17 +
    1.18 +/* Create a "light" -- a yellowish surface with variable alpha */
    1.19 +SDL_Surface *CreateLight(SDL_Surface *screen, int radius)
    1.20 +{
    1.21 +	Uint8  trans, alphamask;
    1.22 +	int    range, addition;
    1.23 +	int    xdist, ydist;
    1.24 +	Uint16 x, y;
    1.25 +	Uint16 skip;
    1.26 +	Uint32 pixel;
    1.27 +	SDL_Surface *light;
    1.28 +
    1.29 +#ifdef LIGHT_16BIT
    1.30 +	Uint16 *buf;
    1.31 +
    1.32 +	/* Create a 16 (4/4/4/4) bpp square with a full 4-bit alpha channel */
    1.33 +	/* Note: this isn't any faster than a 32 bit alpha surface */
    1.34 +	alphamask = 0x0000000F;
    1.35 +	light = SDL_CreateRGBSurface(SDL_SWSURFACE, 2*radius, 2*radius, 16,
    1.36 +			0x0000F000, 0x00000F00, 0x000000F0, alphamask);
    1.37 +#else
    1.38 +	Uint32 *buf;
    1.39 +
    1.40 +	/* Create a 32 (8/8/8/8) bpp square with a full 8-bit alpha channel */
    1.41 +	alphamask = 0x000000FF;
    1.42 +	light = SDL_CreateRGBSurface(SDL_SWSURFACE, 2*radius, 2*radius, 32,
    1.43 +			0xFF000000, 0x00FF0000, 0x0000FF00, alphamask);
    1.44 +	if ( light == NULL ) {
    1.45 +		fprintf(stderr, "Couldn't create light: %s\n", SDL_GetError());
    1.46 +		return(NULL);
    1.47 +	}
    1.48 +#endif
    1.49 +
    1.50 +	/* Fill with a light yellow-orange color */
    1.51 +	skip = light->pitch-(light->w*light->format->BytesPerPixel);
    1.52 +#ifdef LIGHT_16BIT
    1.53 +	buf = (Uint16 *)light->pixels;
    1.54 +#else
    1.55 +	buf = (Uint32 *)light->pixels;
    1.56 +#endif
    1.57 +        /* Get a tranparent pixel value - we'll add alpha later */
    1.58 +	pixel = SDL_MapRGBA(light->format, 0xFF, 0xDD, 0x88, 0);
    1.59 +	for ( y=0; y<light->h; ++y ) {
    1.60 +		for ( x=0; x<light->w; ++x ) {
    1.61 +			*buf++ = pixel;
    1.62 +		}
    1.63 +		buf += skip;	/* Almost always 0, but just in case... */
    1.64 +	}
    1.65 +
    1.66 +	/* Calculate alpha values for the surface. */
    1.67 +#ifdef LIGHT_16BIT
    1.68 +	buf = (Uint16 *)light->pixels;
    1.69 +#else
    1.70 +	buf = (Uint32 *)light->pixels;
    1.71 +#endif
    1.72 +	for ( y=0; y<light->h; ++y ) {
    1.73 +		for ( x=0; x<light->w; ++x ) {
    1.74 +			/* Slow distance formula (from center of light) */
    1.75 +			xdist = x-(light->w/2);
    1.76 +			ydist = y-(light->h/2);
    1.77 +			range = (int)sqrt(xdist*xdist+ydist*ydist);
    1.78 +
    1.79 +			/* Scale distance to range of transparency (0-255) */
    1.80 +			if ( range > radius ) {
    1.81 +				trans = alphamask;
    1.82 +			} else {
    1.83 +				/* Increasing transparency with distance */
    1.84 +				trans = (Uint8)((range*alphamask)/radius);
    1.85 +
    1.86 +				/* Lights are very transparent */
    1.87 +				addition = (alphamask+1)/8;
    1.88 +				if ( (int)trans+addition > alphamask ) {
    1.89 +					trans = alphamask;
    1.90 +				} else {
    1.91 +					trans += addition;
    1.92 +				}
    1.93 +			}
    1.94 +			/* We set the alpha component as the right N bits */
    1.95 +			*buf++ |= (255-trans);
    1.96 +		}
    1.97 +		buf += skip;	/* Almost always 0, but just in case... */
    1.98 +	}
    1.99 +	/* Enable RLE acceleration of this alpha surface */
   1.100 +	SDL_SetAlpha(light, SDL_SRCALPHA|SDL_RLEACCEL, 0);
   1.101 +
   1.102 +	/* We're done! */
   1.103 +	return(light);
   1.104 +}
   1.105 +
   1.106 +static Uint32 flashes = 0;
   1.107 +static Uint32 flashtime = 0;
   1.108 +
   1.109 +void FlashLight(SDL_Surface *screen, SDL_Surface *light, int x, int y)
   1.110 +{
   1.111 +	SDL_Rect position;
   1.112 +	Uint32   ticks1;
   1.113 +	Uint32   ticks2;
   1.114 +
   1.115 +	/* Easy, center light */
   1.116 +	position.x = x-(light->w/2);
   1.117 +	position.y = y-(light->h/2);
   1.118 +	position.w = light->w;
   1.119 +	position.h = light->h;
   1.120 +	ticks1 = SDL_GetTicks();
   1.121 +	SDL_BlitSurface(light, NULL, screen, &position);
   1.122 +	ticks2 = SDL_GetTicks();
   1.123 +	SDL_UpdateRects(screen, 1, &position);
   1.124 +	++flashes;
   1.125 +
   1.126 +	/* Update time spend doing alpha blitting */
   1.127 +	flashtime += (ticks2-ticks1);
   1.128 +}
   1.129 +
   1.130 +static int sprite_visible = 0;
   1.131 +static SDL_Surface *sprite;
   1.132 +static SDL_Surface *backing;
   1.133 +static SDL_Rect    position;
   1.134 +static int         x_vel, y_vel;
   1.135 +static int	   alpha_vel;
   1.136 +
   1.137 +int LoadSprite(SDL_Surface *screen, char *file)
   1.138 +{
   1.139 +	SDL_Surface *converted;
   1.140 +
   1.141 +	/* Load the sprite image */
   1.142 +	sprite = SDL_LoadBMP(file);
   1.143 +	if ( sprite == NULL ) {
   1.144 +		fprintf(stderr, "Couldn't load %s: %s", file, SDL_GetError());
   1.145 +		return(-1);
   1.146 +	}
   1.147 +
   1.148 +	/* Set transparent pixel as the pixel at (0,0) */
   1.149 +	if ( sprite->format->palette ) {
   1.150 +		SDL_SetColorKey(sprite, SDL_SRCCOLORKEY,
   1.151 +						*(Uint8 *)sprite->pixels);
   1.152 +	}
   1.153 +
   1.154 +	/* Convert sprite to video format */
   1.155 +	converted = SDL_DisplayFormat(sprite);
   1.156 +	SDL_FreeSurface(sprite);
   1.157 +	if ( converted == NULL ) {
   1.158 +		fprintf(stderr, "Couldn't convert background: %s\n",
   1.159 +							SDL_GetError());
   1.160 +		return(-1);
   1.161 +	}
   1.162 +	sprite = converted;
   1.163 +
   1.164 +	/* Create the background */
   1.165 +	backing = SDL_CreateRGBSurface(SDL_SWSURFACE, sprite->w, sprite->h, 8,
   1.166 +								0, 0, 0, 0);
   1.167 +	if ( backing == NULL ) {
   1.168 +		fprintf(stderr, "Couldn't create background: %s\n",
   1.169 +							SDL_GetError());
   1.170 +		SDL_FreeSurface(sprite);
   1.171 +		return(-1);
   1.172 +	}
   1.173 +
   1.174 +	/* Convert background to video format */
   1.175 +	converted = SDL_DisplayFormat(backing);
   1.176 +	SDL_FreeSurface(backing);
   1.177 +	if ( converted == NULL ) {
   1.178 +		fprintf(stderr, "Couldn't convert background: %s\n",
   1.179 +							SDL_GetError());
   1.180 +		SDL_FreeSurface(sprite);
   1.181 +		return(-1);
   1.182 +	}
   1.183 +	backing = converted;
   1.184 +
   1.185 +	/* Set the initial position of the sprite */
   1.186 +	position.x = (screen->w-sprite->w)/2;
   1.187 +	position.y = (screen->h-sprite->h)/2;
   1.188 +	position.w = sprite->w;
   1.189 +	position.h = sprite->h;
   1.190 +	x_vel = 0; y_vel = 0;
   1.191 +	alpha_vel = 1;
   1.192 +
   1.193 +	/* We're ready to roll. :) */
   1.194 +	return(0);
   1.195 +}
   1.196 +
   1.197 +void AttractSprite(Uint16 x, Uint16 y)
   1.198 +{
   1.199 +	x_vel = ((int)x-position.x)/10;
   1.200 +	y_vel = ((int)y-position.y)/10;
   1.201 +}
   1.202 +
   1.203 +void MoveSprite(SDL_Surface *screen, SDL_Surface *light)
   1.204 +{
   1.205 +	SDL_Rect updates[2];
   1.206 +	int alpha;
   1.207 +
   1.208 +	/* Erase the sprite if it was visible */
   1.209 +	if ( sprite_visible ) {
   1.210 +		updates[0] = position;
   1.211 +		SDL_BlitSurface(backing, NULL, screen, &updates[0]);
   1.212 +	} else {
   1.213 +		updates[0].x = 0; updates[0].y = 0;
   1.214 +		updates[0].w = 0; updates[0].h = 0;
   1.215 +		sprite_visible = 1;
   1.216 +	}
   1.217 +
   1.218 +	/* Since the sprite is off the screen, we can do other drawing
   1.219 +	   without being overwritten by the saved area behind the sprite.
   1.220 +	 */
   1.221 +	if ( light != NULL ) {
   1.222 +		int x, y;
   1.223 +
   1.224 +		SDL_GetMouseState(&x, &y);
   1.225 +		FlashLight(screen, light, x, y);
   1.226 +	}
   1.227 +	   
   1.228 +	/* Move the sprite, bounce at the wall */
   1.229 +	position.x += x_vel;
   1.230 +	if ( (position.x < 0) || (position.x >= screen->w) ) {
   1.231 +		x_vel = -x_vel;
   1.232 +		position.x += x_vel;
   1.233 +	}
   1.234 +	position.y += y_vel;
   1.235 +	if ( (position.y < 0) || (position.y >= screen->h) ) {
   1.236 +		y_vel = -y_vel;
   1.237 +		position.y += y_vel;
   1.238 +	}
   1.239 +
   1.240 +	/* Update transparency (fade in and out) */
   1.241 +	alpha = sprite->format->alpha;
   1.242 +	if ( (alpha+alpha_vel) < 0 ) {
   1.243 +		alpha_vel = -alpha_vel;
   1.244 +	} else
   1.245 +	if ( (alpha+alpha_vel) > 255 ) {
   1.246 +		alpha_vel = -alpha_vel;
   1.247 +	}
   1.248 +	SDL_SetAlpha(sprite, SDL_SRCALPHA, (Uint8)(alpha+alpha_vel));
   1.249 +
   1.250 +	/* Save the area behind the sprite */
   1.251 +	updates[1] = position;
   1.252 +	SDL_BlitSurface(screen, &updates[1], backing, NULL);
   1.253 +	
   1.254 +	/* Blit the sprite onto the screen */
   1.255 +	updates[1] = position;
   1.256 +	SDL_BlitSurface(sprite, NULL, screen, &updates[1]);
   1.257 +
   1.258 +	/* Make it so! */
   1.259 +	SDL_UpdateRects(screen, 2, updates);
   1.260 +}
   1.261 +
   1.262 +void WarpSprite(SDL_Surface *screen, int x, int y)
   1.263 +{
   1.264 +	SDL_Rect updates[2];
   1.265 +
   1.266 +	/* Erase, move, Draw, update */
   1.267 +	updates[0] = position;
   1.268 +	SDL_BlitSurface(backing, NULL, screen, &updates[0]);
   1.269 +	position.x = x-sprite->w/2;	/* Center about X */
   1.270 +	position.y = y-sprite->h/2;	/* Center about Y */
   1.271 +	updates[1] = position;
   1.272 +	SDL_BlitSurface(screen, &updates[1], backing, NULL);
   1.273 +	updates[1] = position;
   1.274 +	SDL_BlitSurface(sprite, NULL, screen, &updates[1]);
   1.275 +	SDL_UpdateRects(screen, 2, updates);
   1.276 +}
   1.277 +
   1.278 +int main(int argc, char *argv[])
   1.279 +{
   1.280 +	const SDL_VideoInfo *info;
   1.281 +	SDL_Surface *screen;
   1.282 +	Uint8  video_bpp;
   1.283 +	Uint32 videoflags;
   1.284 +	Uint8 *buffer;
   1.285 +	int    i, done;
   1.286 +	SDL_Event event;
   1.287 +	SDL_Surface *light;
   1.288 +	int mouse_pressed;
   1.289 +	Uint32 ticks, lastticks;
   1.290 +
   1.291 +	/* Initialize SDL */
   1.292 +	if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
   1.293 +		fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
   1.294 +		exit(1);
   1.295 +	}
   1.296 +	atexit(SDL_Quit);
   1.297 +
   1.298 +	/* Alpha blending doesn't work well at 8-bit color */
   1.299 +	info = SDL_GetVideoInfo();
   1.300 +	if ( info->vfmt->BitsPerPixel > 8 ) {
   1.301 +		video_bpp = info->vfmt->BitsPerPixel;
   1.302 +	} else {
   1.303 +		video_bpp = 16;
   1.304 +	}
   1.305 +	videoflags = SDL_SWSURFACE;
   1.306 +	while ( argc > 1 ) {
   1.307 +		--argc;
   1.308 +		if ( strcmp(argv[argc-1], "-bpp") == 0 ) {
   1.309 +			video_bpp = atoi(argv[argc]);
   1.310 +			--argc;
   1.311 +		} else
   1.312 +		if ( strcmp(argv[argc], "-hw") == 0 ) {
   1.313 +			videoflags |= SDL_HWSURFACE;
   1.314 +		} else
   1.315 +		if ( strcmp(argv[argc], "-warp") == 0 ) {
   1.316 +			videoflags |= SDL_HWPALETTE;
   1.317 +		} else
   1.318 +		if ( strcmp(argv[argc], "-fullscreen") == 0 ) {
   1.319 +			videoflags |= SDL_FULLSCREEN;
   1.320 +		} else {
   1.321 +			fprintf(stderr, 
   1.322 +			"Usage: %s [-bpp N] [-warp] [-hw] [-fullscreen]\n",
   1.323 +								argv[0]);
   1.324 +			exit(1);
   1.325 +		}
   1.326 +	}
   1.327 +
   1.328 +	/* Set 640x480 video mode */
   1.329 +	if ( (screen=SDL_SetVideoMode(640,480,video_bpp,videoflags)) == NULL ) {
   1.330 +		fprintf(stderr, "Couldn't set 640x480x%d video mode: %s\n",
   1.331 +						video_bpp, SDL_GetError());
   1.332 +		exit(2);
   1.333 +	}
   1.334 +
   1.335 +	/* Set the surface pixels and refresh! */
   1.336 +	if ( SDL_LockSurface(screen) < 0 ) {
   1.337 +		fprintf(stderr, "Couldn't lock the display surface: %s\n",
   1.338 +							SDL_GetError());
   1.339 +		exit(2);
   1.340 +	}
   1.341 +	buffer=(Uint8 *)screen->pixels;
   1.342 +	for ( i=0; i<screen->h; ++i ) {
   1.343 +		memset(buffer,(i*255)/screen->h, screen->pitch);
   1.344 +		buffer += screen->pitch;
   1.345 +	}
   1.346 +	SDL_UnlockSurface(screen);
   1.347 +	SDL_UpdateRect(screen, 0, 0, 0, 0);
   1.348 +
   1.349 +	/* Create the light */
   1.350 +	light = CreateLight(screen, 82);
   1.351 +	if ( light == NULL ) {
   1.352 +		exit(1);
   1.353 +	}
   1.354 +
   1.355 +	/* Load the sprite */
   1.356 +	if ( LoadSprite(screen, "icon.bmp") < 0 ) {
   1.357 +		SDL_FreeSurface(light);
   1.358 +		exit(1);
   1.359 +	}
   1.360 +
   1.361 +	/* Set a clipping rectangle to clip the outside edge of the screen */
   1.362 +	{ SDL_Rect clip;
   1.363 +		clip.x = 32;
   1.364 +		clip.y = 32;
   1.365 +		clip.w = screen->w-(2*32);
   1.366 +		clip.h = screen->h-(2*32);
   1.367 +		SDL_SetClipRect(screen, &clip);
   1.368 +	}
   1.369 +
   1.370 +	/* Wait for a keystroke */
   1.371 +	lastticks = SDL_GetTicks();
   1.372 +	done = 0;
   1.373 +	mouse_pressed = 0;
   1.374 +	while ( !done ) {
   1.375 +		/* Update the frame -- move the sprite */
   1.376 +		if ( mouse_pressed ) {
   1.377 +			MoveSprite(screen, light);
   1.378 +			mouse_pressed = 0;
   1.379 +		} else {
   1.380 +			MoveSprite(screen, NULL);
   1.381 +		}
   1.382 +
   1.383 +		/* Slow down the loop to 30 frames/second */
   1.384 +		ticks = SDL_GetTicks();
   1.385 +		if ( (ticks-lastticks) < FRAME_TICKS ) {
   1.386 +#ifdef CHECK_SLEEP_GRANULARITY
   1.387 +fprintf(stderr, "Sleeping %d ticks\n", FRAME_TICKS-(ticks-lastticks));
   1.388 +#endif
   1.389 +			SDL_Delay(FRAME_TICKS-(ticks-lastticks));
   1.390 +#ifdef CHECK_SLEEP_GRANULARITY
   1.391 +fprintf(stderr, "Slept %d ticks\n", (SDL_GetTicks()-ticks));
   1.392 +#endif
   1.393 +		}
   1.394 +		lastticks = ticks;
   1.395 +
   1.396 +		/* Check for events */
   1.397 +		while ( SDL_PollEvent(&event) ) {
   1.398 +			switch (event.type) {
   1.399 +				/* Attract sprite while mouse is held down */
   1.400 +				case SDL_MOUSEMOTION:
   1.401 +					if (event.motion.state != 0) {
   1.402 +						AttractSprite(event.motion.x,
   1.403 +								event.motion.y);
   1.404 +						mouse_pressed = 1;
   1.405 +					}
   1.406 +					break;
   1.407 +				case SDL_MOUSEBUTTONDOWN:
   1.408 +					if ( event.button.button == 1 ) {
   1.409 +						AttractSprite(event.button.x,
   1.410 +						              event.button.y);
   1.411 +						mouse_pressed = 1;
   1.412 +					} else {
   1.413 +						SDL_Rect area;
   1.414 +
   1.415 +						area.x = event.button.x-16;
   1.416 +						area.y = event.button.y-16;
   1.417 +						area.w = 32;
   1.418 +						area.h = 32;
   1.419 +						SDL_FillRect(screen, &area, 0);
   1.420 +						SDL_UpdateRects(screen,1,&area);
   1.421 +					}
   1.422 +					break;
   1.423 +				case SDL_KEYDOWN:
   1.424 +					/* Any keypress quits the app... */
   1.425 +				case SDL_QUIT:
   1.426 +					done = 1;
   1.427 +					break;
   1.428 +				default:
   1.429 +					break;
   1.430 +			}
   1.431 +		}
   1.432 +	}
   1.433 +	SDL_FreeSurface(light);
   1.434 +	SDL_FreeSurface(sprite);
   1.435 +	SDL_FreeSurface(backing);
   1.436 +
   1.437 +	/* Print out some timing information */
   1.438 +	if ( flashes > 0 ) {
   1.439 +		printf("%d alpha blits, ~%4.4f ms per blit\n", 
   1.440 +			flashes, (float)flashtime/flashes);
   1.441 +	}
   1.442 +	return(0);
   1.443 +}