test/testsprite.c
author Patrice Mandin <patmandin@gmail.com>
Thu, 19 Jan 2006 21:28:52 +0000
changeset 1257 448a9a64537b
parent 1214 31103dbf1c26
child 1516 4d241ea8a1cd
permissions -rw-r--r--
[PATCH] SDL_GetVideoMode() does not find best mode, part 2

Following commit 1.51, I come accross a problem when SDL must choose between
several video modes that could suit the one asked.

If I ask 320x240 with this list:
768x480 768x240 640x400 640x200 384x480 384x240 320x400 320x200

The smallest selectables modes are 384x240 and 320x400. And SDL choose the later
in this list, but 384x240 is more suitable. So I added a check to compare
the pixel count (surface) of modes, and select the one which has the smallest
pixel count.

In my example, 384x240 has 92160 pixels, and 320x400 has 128000 pixels. So now
SDL will choose 384x240 for the asked 320x240 mode.
     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(SDL_Surface *screen, 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(screen, "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 }