Mercurial > sdl-ios-xcode
diff test/testalpha.c @ 0:74212992fb08
Initial revision
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 26 Apr 2001 16:45:43 +0000 |
parents | |
children | 609543e2b3a1 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testalpha.c Thu Apr 26 16:45:43 2001 +0000 @@ -0,0 +1,440 @@ + +/* Simple program: Fill a colormap with gray and stripe it down the screen, + Then move an alpha valued sprite around the screen. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "SDL.h" + +#define FRAME_TICKS (1000/30) /* 30 frames/second */ + +/* Create a "light" -- a yellowish surface with variable alpha */ +SDL_Surface *CreateLight(SDL_Surface *screen, int radius) +{ + Uint8 trans, alphamask; + int range, addition; + int xdist, ydist; + Uint16 x, y; + Uint16 skip; + Uint32 pixel; + SDL_Surface *light; + +#ifdef LIGHT_16BIT + Uint16 *buf; + + /* Create a 16 (4/4/4/4) bpp square with a full 4-bit alpha channel */ + /* Note: this isn't any faster than a 32 bit alpha surface */ + alphamask = 0x0000000F; + light = SDL_CreateRGBSurface(SDL_SWSURFACE, 2*radius, 2*radius, 16, + 0x0000F000, 0x00000F00, 0x000000F0, alphamask); +#else + Uint32 *buf; + + /* Create a 32 (8/8/8/8) bpp square with a full 8-bit alpha channel */ + alphamask = 0x000000FF; + light = SDL_CreateRGBSurface(SDL_SWSURFACE, 2*radius, 2*radius, 32, + 0xFF000000, 0x00FF0000, 0x0000FF00, alphamask); + if ( light == NULL ) { + fprintf(stderr, "Couldn't create light: %s\n", SDL_GetError()); + return(NULL); + } +#endif + + /* Fill with a light yellow-orange color */ + skip = light->pitch-(light->w*light->format->BytesPerPixel); +#ifdef LIGHT_16BIT + buf = (Uint16 *)light->pixels; +#else + buf = (Uint32 *)light->pixels; +#endif + /* Get a tranparent pixel value - we'll add alpha later */ + pixel = SDL_MapRGBA(light->format, 0xFF, 0xDD, 0x88, 0); + for ( y=0; y<light->h; ++y ) { + for ( x=0; x<light->w; ++x ) { + *buf++ = pixel; + } + buf += skip; /* Almost always 0, but just in case... */ + } + + /* Calculate alpha values for the surface. */ +#ifdef LIGHT_16BIT + buf = (Uint16 *)light->pixels; +#else + buf = (Uint32 *)light->pixels; +#endif + for ( y=0; y<light->h; ++y ) { + for ( x=0; x<light->w; ++x ) { + /* Slow distance formula (from center of light) */ + xdist = x-(light->w/2); + ydist = y-(light->h/2); + range = (int)sqrt(xdist*xdist+ydist*ydist); + + /* Scale distance to range of transparency (0-255) */ + if ( range > radius ) { + trans = alphamask; + } else { + /* Increasing transparency with distance */ + trans = (Uint8)((range*alphamask)/radius); + + /* Lights are very transparent */ + addition = (alphamask+1)/8; + if ( (int)trans+addition > alphamask ) { + trans = alphamask; + } else { + trans += addition; + } + } + /* We set the alpha component as the right N bits */ + *buf++ |= (255-trans); + } + buf += skip; /* Almost always 0, but just in case... */ + } + /* Enable RLE acceleration of this alpha surface */ + SDL_SetAlpha(light, SDL_SRCALPHA|SDL_RLEACCEL, 0); + + /* We're done! */ + return(light); +} + +static Uint32 flashes = 0; +static Uint32 flashtime = 0; + +void FlashLight(SDL_Surface *screen, SDL_Surface *light, int x, int y) +{ + SDL_Rect position; + Uint32 ticks1; + Uint32 ticks2; + + /* Easy, center light */ + position.x = x-(light->w/2); + position.y = y-(light->h/2); + position.w = light->w; + position.h = light->h; + ticks1 = SDL_GetTicks(); + SDL_BlitSurface(light, NULL, screen, &position); + ticks2 = SDL_GetTicks(); + SDL_UpdateRects(screen, 1, &position); + ++flashes; + + /* Update time spend doing alpha blitting */ + flashtime += (ticks2-ticks1); +} + +static int sprite_visible = 0; +static SDL_Surface *sprite; +static SDL_Surface *backing; +static SDL_Rect position; +static int x_vel, y_vel; +static int alpha_vel; + +int LoadSprite(SDL_Surface *screen, char *file) +{ + SDL_Surface *converted; + + /* Load the sprite image */ + sprite = SDL_LoadBMP(file); + if ( sprite == NULL ) { + fprintf(stderr, "Couldn't load %s: %s", file, SDL_GetError()); + return(-1); + } + + /* Set transparent pixel as the pixel at (0,0) */ + if ( sprite->format->palette ) { + SDL_SetColorKey(sprite, SDL_SRCCOLORKEY, + *(Uint8 *)sprite->pixels); + } + + /* Convert sprite to video format */ + converted = SDL_DisplayFormat(sprite); + SDL_FreeSurface(sprite); + if ( converted == NULL ) { + fprintf(stderr, "Couldn't convert background: %s\n", + SDL_GetError()); + return(-1); + } + sprite = converted; + + /* Create the background */ + backing = SDL_CreateRGBSurface(SDL_SWSURFACE, sprite->w, sprite->h, 8, + 0, 0, 0, 0); + if ( backing == NULL ) { + fprintf(stderr, "Couldn't create background: %s\n", + SDL_GetError()); + SDL_FreeSurface(sprite); + return(-1); + } + + /* Convert background to video format */ + converted = SDL_DisplayFormat(backing); + SDL_FreeSurface(backing); + if ( converted == NULL ) { + fprintf(stderr, "Couldn't convert background: %s\n", + SDL_GetError()); + SDL_FreeSurface(sprite); + return(-1); + } + backing = converted; + + /* Set the initial position of the sprite */ + position.x = (screen->w-sprite->w)/2; + position.y = (screen->h-sprite->h)/2; + position.w = sprite->w; + position.h = sprite->h; + x_vel = 0; y_vel = 0; + alpha_vel = 1; + + /* We're ready to roll. :) */ + return(0); +} + +void AttractSprite(Uint16 x, Uint16 y) +{ + x_vel = ((int)x-position.x)/10; + y_vel = ((int)y-position.y)/10; +} + +void MoveSprite(SDL_Surface *screen, SDL_Surface *light) +{ + SDL_Rect updates[2]; + int alpha; + + /* Erase the sprite if it was visible */ + if ( sprite_visible ) { + updates[0] = position; + SDL_BlitSurface(backing, NULL, screen, &updates[0]); + } else { + updates[0].x = 0; updates[0].y = 0; + updates[0].w = 0; updates[0].h = 0; + sprite_visible = 1; + } + + /* Since the sprite is off the screen, we can do other drawing + without being overwritten by the saved area behind the sprite. + */ + if ( light != NULL ) { + int x, y; + + SDL_GetMouseState(&x, &y); + FlashLight(screen, light, x, y); + } + + /* Move the sprite, bounce at the wall */ + position.x += x_vel; + if ( (position.x < 0) || (position.x >= screen->w) ) { + x_vel = -x_vel; + position.x += x_vel; + } + position.y += y_vel; + if ( (position.y < 0) || (position.y >= screen->h) ) { + y_vel = -y_vel; + position.y += y_vel; + } + + /* Update transparency (fade in and out) */ + alpha = sprite->format->alpha; + if ( (alpha+alpha_vel) < 0 ) { + alpha_vel = -alpha_vel; + } else + if ( (alpha+alpha_vel) > 255 ) { + alpha_vel = -alpha_vel; + } + SDL_SetAlpha(sprite, SDL_SRCALPHA, (Uint8)(alpha+alpha_vel)); + + /* Save the area behind the sprite */ + updates[1] = position; + SDL_BlitSurface(screen, &updates[1], backing, NULL); + + /* Blit the sprite onto the screen */ + updates[1] = position; + SDL_BlitSurface(sprite, NULL, screen, &updates[1]); + + /* Make it so! */ + SDL_UpdateRects(screen, 2, updates); +} + +void WarpSprite(SDL_Surface *screen, int x, int y) +{ + SDL_Rect updates[2]; + + /* Erase, move, Draw, update */ + updates[0] = position; + SDL_BlitSurface(backing, NULL, screen, &updates[0]); + position.x = x-sprite->w/2; /* Center about X */ + position.y = y-sprite->h/2; /* Center about Y */ + updates[1] = position; + SDL_BlitSurface(screen, &updates[1], backing, NULL); + updates[1] = position; + SDL_BlitSurface(sprite, NULL, screen, &updates[1]); + SDL_UpdateRects(screen, 2, updates); +} + +int main(int argc, char *argv[]) +{ + const SDL_VideoInfo *info; + SDL_Surface *screen; + Uint8 video_bpp; + Uint32 videoflags; + Uint8 *buffer; + int i, done; + SDL_Event event; + SDL_Surface *light; + int mouse_pressed; + Uint32 ticks, lastticks; + + /* Initialize SDL */ + if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + + /* Alpha blending doesn't work well at 8-bit color */ + info = SDL_GetVideoInfo(); + if ( info->vfmt->BitsPerPixel > 8 ) { + video_bpp = info->vfmt->BitsPerPixel; + } else { + video_bpp = 16; + } + videoflags = SDL_SWSURFACE; + while ( argc > 1 ) { + --argc; + if ( strcmp(argv[argc-1], "-bpp") == 0 ) { + video_bpp = atoi(argv[argc]); + --argc; + } else + if ( strcmp(argv[argc], "-hw") == 0 ) { + videoflags |= SDL_HWSURFACE; + } else + if ( strcmp(argv[argc], "-warp") == 0 ) { + videoflags |= SDL_HWPALETTE; + } else + if ( strcmp(argv[argc], "-fullscreen") == 0 ) { + videoflags |= SDL_FULLSCREEN; + } else { + fprintf(stderr, + "Usage: %s [-bpp N] [-warp] [-hw] [-fullscreen]\n", + argv[0]); + exit(1); + } + } + + /* Set 640x480 video mode */ + if ( (screen=SDL_SetVideoMode(640,480,video_bpp,videoflags)) == NULL ) { + fprintf(stderr, "Couldn't set 640x480x%d video mode: %s\n", + video_bpp, SDL_GetError()); + exit(2); + } + + /* Set the surface pixels and refresh! */ + if ( SDL_LockSurface(screen) < 0 ) { + fprintf(stderr, "Couldn't lock the display surface: %s\n", + SDL_GetError()); + exit(2); + } + buffer=(Uint8 *)screen->pixels; + for ( i=0; i<screen->h; ++i ) { + memset(buffer,(i*255)/screen->h, screen->pitch); + buffer += screen->pitch; + } + SDL_UnlockSurface(screen); + SDL_UpdateRect(screen, 0, 0, 0, 0); + + /* Create the light */ + light = CreateLight(screen, 82); + if ( light == NULL ) { + exit(1); + } + + /* Load the sprite */ + if ( LoadSprite(screen, "icon.bmp") < 0 ) { + SDL_FreeSurface(light); + exit(1); + } + + /* Set a clipping rectangle to clip the outside edge of the screen */ + { SDL_Rect clip; + clip.x = 32; + clip.y = 32; + clip.w = screen->w-(2*32); + clip.h = screen->h-(2*32); + SDL_SetClipRect(screen, &clip); + } + + /* Wait for a keystroke */ + lastticks = SDL_GetTicks(); + done = 0; + mouse_pressed = 0; + while ( !done ) { + /* Update the frame -- move the sprite */ + if ( mouse_pressed ) { + MoveSprite(screen, light); + mouse_pressed = 0; + } else { + MoveSprite(screen, NULL); + } + + /* Slow down the loop to 30 frames/second */ + ticks = SDL_GetTicks(); + if ( (ticks-lastticks) < FRAME_TICKS ) { +#ifdef CHECK_SLEEP_GRANULARITY +fprintf(stderr, "Sleeping %d ticks\n", FRAME_TICKS-(ticks-lastticks)); +#endif + SDL_Delay(FRAME_TICKS-(ticks-lastticks)); +#ifdef CHECK_SLEEP_GRANULARITY +fprintf(stderr, "Slept %d ticks\n", (SDL_GetTicks()-ticks)); +#endif + } + lastticks = ticks; + + /* Check for events */ + while ( SDL_PollEvent(&event) ) { + switch (event.type) { + /* Attract sprite while mouse is held down */ + case SDL_MOUSEMOTION: + if (event.motion.state != 0) { + AttractSprite(event.motion.x, + event.motion.y); + mouse_pressed = 1; + } + break; + case SDL_MOUSEBUTTONDOWN: + if ( event.button.button == 1 ) { + AttractSprite(event.button.x, + event.button.y); + mouse_pressed = 1; + } else { + SDL_Rect area; + + area.x = event.button.x-16; + area.y = event.button.y-16; + area.w = 32; + area.h = 32; + SDL_FillRect(screen, &area, 0); + SDL_UpdateRects(screen,1,&area); + } + break; + case SDL_KEYDOWN: + /* Any keypress quits the app... */ + case SDL_QUIT: + done = 1; + break; + default: + break; + } + } + } + SDL_FreeSurface(light); + SDL_FreeSurface(sprite); + SDL_FreeSurface(backing); + + /* Print out some timing information */ + if ( flashes > 0 ) { + printf("%d alpha blits, ~%4.4f ms per blit\n", + flashes, (float)flashtime/flashes); + } + return(0); +}