1 /* Simple program: Move N sprites around on the screen as fast as possible */ 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <ctype.h> 7 #include <math.h> 8 #include <time.h> 9 10 #include "SDL.h" 11 12 #define NUM_SPRITES 100 13 #define MAX_SPEED 1 14 15 SDL_Surface *sprite; 16 int numsprites; 17 SDL_Rect *sprite_rects; 18 SDL_Rect *positions; 19 SDL_Rect *velocities; 20 int sprites_visible; 21 int debug_flip; 22 Uint16 sprite_w, sprite_h; 23 24 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 25 static void quit(int rc) 26 { 27 SDL_Quit(); 28 exit(rc); 29 } 30 31 int LoadSprite(char *file) 32 { 33 SDL_Surface *temp; 34 35 /* Load the sprite image */ 36 sprite = SDL_LoadBMP(file); 37 if ( sprite == NULL ) { 38 fprintf(stderr, "Couldn't load %s: %s", file, SDL_GetError()); 39 return(-1); 40 } 41 42 /* Set transparent pixel as the pixel at (0,0) */ 43 if ( sprite->format->palette ) { 44 SDL_SetColorKey(sprite, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 45 *(Uint8 *)sprite->pixels); 46 } 47 48 /* Convert sprite to video format */ 49 temp = SDL_DisplayFormat(sprite); 50 SDL_FreeSurface(sprite); 51 if ( temp == NULL ) { 52 fprintf(stderr, "Couldn't convert background: %s\n", 53 SDL_GetError()); 54 return(-1); 55 } 56 sprite = temp; 57 58 /* We're ready to roll. :) */ 59 return(0); 60 } 61 62 void MoveSprites(SDL_Surface *screen, Uint32 background) 63 { 64 int i, nupdates; 65 SDL_Rect area, *position, *velocity; 66 67 nupdates = 0; 68 /* Erase all the sprites if necessary */ 69 if ( sprites_visible ) { 70 SDL_FillRect(screen, NULL, background); 71 } 72 73 /* Move the sprite, bounce at the wall, and draw */ 74 for ( i=0; i<numsprites; ++i ) { 75 position = &positions[i]; 76 velocity = &velocities[i]; 77 position->x += velocity->x; 78 if ( (position->x < 0) || (position->x >= (screen->w - sprite_w)) ) { 79 velocity->x = -velocity->x; 80 position->x += velocity->x; 81 } 82 position->y += velocity->y; 83 if ( (position->y < 0) || (position->y >= (screen->h - sprite_w)) ) { 84 velocity->y = -velocity->y; 85 position->y += velocity->y; 86 } 87 88 /* Blit the sprite onto the screen */ 89 area = *position; 90 SDL_BlitSurface(sprite, NULL, screen, &area); 91 sprite_rects[nupdates++] = area; 92 } 93 94 if (debug_flip) { 95 if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) { 96 static int t = 0; 97 98 Uint32 color = SDL_MapRGB (screen->format, 255, 0, 0); 99 SDL_Rect r; 100 r.x = (sin((float)t * 2 * 3.1459) + 1.0) / 2.0 * (screen->w-20); 101 r.y = 0; 102 r.w = 20; 103 r.h = screen->h; 104 105 SDL_FillRect (screen, &r, color); 106 t+=2; 107 } 108 } 109 110 /* Update the screen! */ 111 if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) { 112 SDL_Flip(screen); 113 } else { 114 SDL_UpdateRects(screen, nupdates, sprite_rects); 115 } 116 sprites_visible = 1; 117 } 118 119 /* This is a way of telling whether or not to use hardware surfaces */ 120 Uint32 FastestFlags(Uint32 flags, int width, int height, int bpp) 121 { 122 const SDL_VideoInfo *info; 123 124 /* Hardware acceleration is only used in fullscreen mode */ 125 flags |= SDL_FULLSCREEN; 126 127 /* Check for various video capabilities */ 128 info = SDL_GetVideoInfo(); 129 if ( info->blit_hw_CC && info->blit_fill ) { 130 /* We use accelerated colorkeying and color filling */ 131 flags |= SDL_HWSURFACE; 132 } 133 /* If we have enough video memory, and will use accelerated 134 blits directly to it, then use page flipping. 135 */ 136 if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { 137 /* Direct hardware blitting without double-buffering 138 causes really bad flickering. 139 */ 140 if ( info->video_mem*1024 > (height*width*bpp/8) ) { 141 flags |= SDL_DOUBLEBUF; 142 } else { 143 flags &= ~SDL_HWSURFACE; 144 } 145 } 146 147 /* Return the flags */ 148 return(flags); 149 } 150 151 int main(int argc, char *argv[]) 152 { 153 SDL_Surface *screen; 154 Uint8 *mem; 155 int width, height; 156 Uint8 video_bpp; 157 Uint32 videoflags; 158 Uint32 background; 159 int i, done; 160 SDL_Event event; 161 Uint32 then, now, frames; 162 163 /* Initialize SDL */ 164 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { 165 fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError()); 166 return(1); 167 } 168 169 numsprites = NUM_SPRITES; 170 videoflags = SDL_SWSURFACE|SDL_ANYFORMAT; 171 width = 640; 172 height = 480; 173 video_bpp = 8; 174 debug_flip = 0; 175 while ( argc > 1 ) { 176 --argc; 177 if ( strcmp(argv[argc-1], "-width") == 0 ) { 178 width = atoi(argv[argc]); 179 --argc; 180 } else 181 if ( strcmp(argv[argc-1], "-height") == 0 ) { 182 height = atoi(argv[argc]); 183 --argc; 184 } else 185 if ( strcmp(argv[argc-1], "-bpp") == 0 ) { 186 video_bpp = atoi(argv[argc]); 187 videoflags &= ~SDL_ANYFORMAT; 188 --argc; 189 } else 190 if ( strcmp(argv[argc], "-fast") == 0 ) { 191 videoflags = FastestFlags(videoflags, width, height, video_bpp); 192 } else 193 if ( strcmp(argv[argc], "-hw") == 0 ) { 194 videoflags ^= SDL_HWSURFACE; 195 } else 196 if ( strcmp(argv[argc], "-flip") == 0 ) { 197 videoflags ^= SDL_DOUBLEBUF; 198 } else 199 if ( strcmp(argv[argc], "-debugflip") == 0 ) { 200 debug_flip ^= 1; 201 } else 202 if ( strcmp(argv[argc], "-fullscreen") == 0 ) { 203 videoflags ^= SDL_FULLSCREEN; 204 } else 205 if ( isdigit(argv[argc][0]) ) { 206 numsprites = atoi(argv[argc]); 207 } else { 208 fprintf(stderr, 209 "Usage: %s [-bpp N] [-hw] [-flip] [-fast] [-fullscreen] [numsprites]\n", 210 argv[0]); 211 quit(1); 212 } 213 } 214 215 /* Set video mode */ 216 screen = SDL_SetVideoMode(width, height, video_bpp, videoflags); 217 if ( ! screen ) { 218 fprintf(stderr, "Couldn't set %dx%d video mode: %s\n", 219 width, height, SDL_GetError()); 220 quit(2); 221 } 222 223 /* Load the sprite */ 224 if ( LoadSprite("icon.bmp") < 0 ) { 225 quit(1); 226 } 227 228 /* Allocate memory for the sprite info */ 229 mem = (Uint8 *)malloc(4*sizeof(SDL_Rect)*numsprites); 230 if ( mem == NULL ) { 231 SDL_FreeSurface(sprite); 232 fprintf(stderr, "Out of memory!\n"); 233 quit(2); 234 } 235 sprite_rects = (SDL_Rect *)mem; 236 positions = sprite_rects; 237 sprite_rects += numsprites; 238 velocities = sprite_rects; 239 sprite_rects += numsprites; 240 sprite_w = sprite->w; 241 sprite_h = sprite->h; 242 srand(time(NULL)); 243 for ( i=0; i<numsprites; ++i ) { 244 positions[i].x = rand()%(screen->w - sprite_w); 245 positions[i].y = rand()%(screen->h - sprite_h); 246 positions[i].w = sprite->w; 247 positions[i].h = sprite->h; 248 velocities[i].x = 0; 249 velocities[i].y = 0; 250 while ( ! velocities[i].x && ! velocities[i].y ) { 251 velocities[i].x = (rand()%(MAX_SPEED*2+1))-MAX_SPEED; 252 velocities[i].y = (rand()%(MAX_SPEED*2+1))-MAX_SPEED; 253 } 254 } 255 background = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00); 256 257 /* Print out information about our surfaces */ 258 printf("Screen is at %d bits per pixel\n",screen->format->BitsPerPixel); 259 if ( (screen->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { 260 printf("Screen is in video memory\n"); 261 } else { 262 printf("Screen is in system memory\n"); 263 } 264 if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) { 265 printf("Screen has double-buffering enabled\n"); 266 } 267 if ( (sprite->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { 268 printf("Sprite is in video memory\n"); 269 } else { 270 printf("Sprite is in system memory\n"); 271 } 272 /* Run a sample blit to trigger blit acceleration */ 273 { SDL_Rect dst; 274 dst.x = 0; 275 dst.y = 0; 276 dst.w = sprite->w; 277 dst.h = sprite->h; 278 SDL_BlitSurface(sprite, NULL, screen, &dst); 279 SDL_FillRect(screen, &dst, background); 280 } 281 if ( (sprite->flags & SDL_HWACCEL) == SDL_HWACCEL ) { 282 printf("Sprite blit uses hardware acceleration\n"); 283 } 284 if ( (sprite->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) { 285 printf("Sprite blit uses RLE acceleration\n"); 286 } 287 288 /* Loop, blitting sprites and waiting for a keystroke */ 289 frames = 0; 290 then = SDL_GetTicks(); 291 done = 0; 292 sprites_visible = 0; 293 while ( !done ) { 294 /* Check for events */ 295 ++frames; 296 while ( SDL_PollEvent(&event) ) { 297 switch (event.type) { 298 case SDL_MOUSEBUTTONDOWN: 299 SDL_WarpMouse(screen->w/2, screen->h/2); 300 break; 301 case SDL_KEYDOWN: 302 /* Any keypress quits the app... */ 303 case SDL_QUIT: 304 done = 1; 305 break; 306 default: 307 break; 308 } 309 } 310 MoveSprites(screen, background); 311 } 312 SDL_FreeSurface(sprite); 313 free(mem); 314 315 /* Print out some timing information */ 316 now = SDL_GetTicks(); 317 if ( now > then ) { 318 printf("%2.2f frames per second\n", 319 ((double)frames*1000)/(now-then)); 320 } 321 SDL_Quit(); 322 return(0); 323 } 324